Union타입에서 더욱 구체적인 타입으로 논리적으로 유추 할 수 있게 되는 걸 의미한다.
예를 들어서
let numberOrString: number | string = 'Code Factory';
numberOrString;
const decimal = 12.375;
console.log(decimal.toFixed(2)); //number에만 쓸 수 있는 기능이다.
// numberOrString.toFixed(); //에러발생
numberOrString을 확인해보면 string으로 내로잉이 된것을 볼 수 있다.
타입스크립트는 우리가 타입을 number | string이라고 선언을 했어도 값을 통해서 어떤 타입이 될지를 유추를 한다.
let numOrString: number | string = '아이유';
numberOrString.toString(); // 타입이 string으로 내로잉이 되어있음
numOrString 변수의 타입을 number | string으로 선언하였지만 값은 string이다.
이 때 string으로 내로잉이 발생한다.
numberOrString = Math.random() > 0.5 ? 1123 : '아이유';
// 빌드하는 순간에는 지금 숫자가 반환이될지 스트링이 반환이 될지 알 수가 없음
//여기선 string | number로 돌아옴
if(typeof numberOrString === 'string'){
numberOrString; //string 타입으로 네로잉
}else{
numberOrString // number타입으로 네로잉
}
numberOrString은 number가 될 지 string이 될지 모른다. 그래서 처음엔 string | number가 된다.
하지만 if문에 들어가면 달라지게 된다.
typeof string이라면 무조건 string이 될 것이고 else는 당연하게 number가 된다.
string으로 내로잉이 되었다.
number로 내로잉이 되었다.
let nullOrString: null | string[] = Math.random() > 0.5 ? null : ['아이유', '레드벨벳'];
if(nullOrString){
nullOrString; // string[]
}else{
nullOrString; //null
}
if문에서 null이면 false고 null아니면 true가 나온다.
즉 true이면 string[]으로 내로잉이되고
false이면 null로 내로잉이 된다.
let numberOrString2 : number | string = Math.random() > 0.5 ? 1123 : '아이유';
let stringOrBool2 : string | boolean = Math.random() > 0.5 ? '아이브': true;
if(numberOrString2 === stringOrBool2){
numberOrString2; //string타입
stringOrBool2 //string 타입
}else{
numberOrString2; //string | number타입
stringOrBool2 //string | true타입
}
numberOrString2타입과 stringOrBool2타입과 에서 공통된 타입은 string타입말곤 없다.
즉 같을 때에는 string타입으로 내로잉이 되고
그렇지 않을 때에는 각자 타입으로 내로잉이 된다.
interface Human{
name:string;
age:number;
}
interface Dog{
name:string;
type : string;
}
let human: Human = {
name:'안유진',
age:20,
}
let dog:Dog={
name:'오리',
type:'qweqweqw'
}
let humanOrDog : Human | Dog = Math.random() > 0.5 ? human : dog;
console.log('name' in human);
if ( 'type' in humanOrDog){
humanOrDog; //Dog 내로잉
}else{
humanOrDog; //Human 내로잉
}
humanOrDog는 유니온을 통해 Human타입과 Dog타입을 가질 수 있다.
하지만 속성 중에 type이 있는지 체크를 해서 존재한다면 Dog로 내로잉(Dog만 type을 가지고 있기 때문)이 되고
그렇지 않을 때에는 자연스럽게 Dog가 아닌 Human타입으로 내로잉이 된다.
let dateOrString: Date | string = Math.random() > 0.5 ? new Date() : '코드팩토리';
if(dateOrString instanceof Date){
dateOrString; //Date
}else{
dateOrString //string
}
마찬가지로 dateOrString은 Date타입과 string타입으로 유니온 되어 있지만
if문을 통해 구체적으로 내로잉 된 것을 볼 수 있다.
interface Animal{
type : 'dog' | 'human';
height? : number;
//강아지의 종
breed? : string;
} // 좋은 방법아님
let animal: Animal = Math.random() > 0.5?
{
type:'human',
height:177
}:
{
type:"dog",
breed:'wqeqweqw'
}
if (animal.type ==='human'){
animal.height
}else{
animal.height;
animal.breed;
}
// 인터페이스 분리하기 좋은 방법
interface Human2{
type: 'human';
height : number;
}
interface Dog2{
type:"dog",
breed : string; //옵셔널 기능 사라짐
}
interface Fish2{
type:'fish',
length:number
}
type HumanOrDog2 = Human2 | Dog2 | Fish2;
let humanOrDog2 : HumanOrDog2 = Math.random() > 0.5 ?
{
type:'human',
height:177,
} : Math.random() > 0.5 ?
{
type:"dog",
breed:'wqeqweqw'
} : {
type:"fish",
length : 8
}
if(humanOrDog2.type === 'human'){
humanOrDog2 //Human2
}else{
humanOrDog2; // Dog2 | Fish2
}
여기서 interface를 하나로 뭉튼 그려가지고 선언을 하는것보다 여러개로 나누너서 선언을 한 다음에 유니언으로 묶어주는게 타입을 정확히 유추하는데 훨씬 더 유리하다.
switch(humanOrDog2.type){
case 'human':
humanOrDog2; //Human2
break;
case 'dog':
humanOrDog2; //Dog2
break;
case 'fish':
humanOrDog2; //Fish2
break;
default:
humanOrDog2; //never
const _check : never = humanOrDog2
break;
}
즉 내로잉은 TS에서 자동적으로 타입을 구체화 해주는 기능 같다.