내로잉(Narrowing)

홍범선·2023년 10월 21일
0

타입스크립트

목록 보기
9/34

네로잉이란?

Union타입에서 더욱 구체적인 타입으로 논리적으로 유추 할 수 있게 되는 걸 의미한다.

예를 들어서

let numberOrString: number | string = 'Code Factory';
numberOrString;

const decimal = 12.375;
console.log(decimal.toFixed(2)); //number에만 쓸 수 있는 기능이다.

// numberOrString.toFixed(); //에러발생


numberOrString을 확인해보면 string으로 내로잉이 된것을 볼 수 있다.
타입스크립트는 우리가 타입을 number | string이라고 선언을 했어도 값을 통해서 어떤 타입이 될지를 유추를 한다.

네로잉 종류

  • 1) Assignment Narrowing
  • 2) typeof Narrowing
  • 3) Truthiness Narrowing
  • 4) Equality
  • 5) in operator
  • 6) instanceof
  • 7) discrimate union narrowing (차별된 유니언 내로잉)
  • 8) exhautiveness checking

(1) Assignment Narrowing

let numOrString: number | string = '아이유';
numberOrString.toString(); // 타입이 string으로 내로잉이 되어있음

numOrString 변수의 타입을 number | string으로 선언하였지만 값은 string이다.
이 때 string으로 내로잉이 발생한다.

(2) typeof narrowing

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로 내로잉이 되었다.

(3) Truthiness Narrowing

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로 내로잉이 된다.

(4) Equality Narrowing

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타입으로 내로잉이 되고
그렇지 않을 때에는 각자 타입으로 내로잉이 된다.

(5) in operator narrowing

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타입으로 내로잉이 된다.

(6) instacneof narrowing

let dateOrString: Date | string = Math.random() > 0.5 ? new Date() : '코드팩토리';

if(dateOrString instanceof Date){
  dateOrString; //Date
}else{
  dateOrString //string
}

마찬가지로 dateOrString은 Date타입과 string타입으로 유니온 되어 있지만
if문을 통해 구체적으로 내로잉 된 것을 볼 수 있다.

(7) Discriminated Union Narrowing

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를 하나로 뭉튼 그려가지고 선언을 하는것보다 여러개로 나누너서 선언을 한 다음에 유니언으로 묶어주는게 타입을 정확히 유추하는데 훨씬 더 유리하다.

(8) Exhuastiveness Checking

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에서 자동적으로 타입을 구체화 해주는 기능 같다.

profile
알고리즘 정리 블로그입니다.

0개의 댓글