// 숫자 데이터타입인지 아닌지 알아내는 함수
// true 또는 false 만 알수 있다.
// 리턴값의 타입은 알수 없다.
// 리턴값의 타입을 알아낼 수는 없을까?
function isNumber(변수명: any) {
  return typeof 변수명 === "number";
}
// let a: boolean
// 나는 a 가 number 라고 타입이 추론되기를 원했다.
// 그런데 a가 boolean 이다.
// 타입을 알아낼 수 없네.
let a = isNumber(123);

// let b: boolean
let b = isNumber("안녕");

// 나는 true / false 가 아니고
// 리턴되는 값의 타입을 알고 싶다.
// 그때 사용하는 게 타입 프리디케이트이다.
function isNumber2(변수명: any): 변수명 is number {
  return typeof 변수명 === "number";
}
// let a2: number
let a2 = 123;
if (isNumber2(a2)) {
  // let a2: number
  a2;
}

// let b2: string
let b2 = "안녕";

if (isNumber2(b2)) {
  // let b2: never;
  // 예는 원래 string 이었는데 never 로 변경되었다.
  // never 는 존재할 수 없는 타입이다.
  b2;
}

/**
 * interface 에서 타입알아내기
 */
interface Dog {
  name: string;
  age: number;
}
interface Cat {
  name: string;
  breed: string;
}
type DogOrCat = Dog | Cat;

// 나는 Dog 타입인지, Cat 타입인지 정확히 타입을 좁히고 싶다.
// Dog 타입이라면 Dog 에 대한 코딩 처리
// Cat 이라면 Cat 에 대한 코딩 처리
// 여기서는 true/false 가 아닌 타입을 리턴 받고 싶다.

// boolean 리턴
function isDog(변수명: DogOrCat): boolean {
  return (변수명 as Dog).age !== undefined;
}

// type 리턴
function isDogTypeReturn(변수명: DogOrCat): 변수명 is Dog {
  return (변수명 as Dog).age !== undefined;
}

const doge: DogOrCat = { name: "강아지", age: 5 };
// true / false 체크 및 boolean
// 분명히 const doge: DogOrCat 라고 타입을 정의했다.
if (isDog(doge) === true) {
  // 타입 좁히기 성공
  // const doge: Dog
  doge;
  doge.age;
} else {
  // const doge: Dog 라고 나오면 이상한거 아닌가요?
  doge;
  doge.age;
}
// 타입 체크 및 타입 리턴
// 분명히 const doge: DogOrCat 라고 타입을 정의했다.
// 아래 구문에서는
// const doge: Dog 로 변환이 된다.
if (isDogTypeReturn(doge)) {
  // 정확히 Dog 타입이 확인 되었으므로 dog 에 대한 코딩 처리 가능..
  doge;
  doge.age;
} else {
  // const doge: never 로 추론됨
  // 아래는 타입이 never 로 변경되서 Dog 속성 사용 불가.
  doge;
  doge.age; // 오류 정확히 타입 체크 했으므로 오류가 맞다.
}