본문 바로가기

Front-End: Web/TypeScript

[코딩애플] ts part 2-2. Type Narrowng(2)

반응형

Narrowing 할 수 있는 방법 더 알아보기

typeof 연산자로는 부족하다

Narrowing할 때 typeof 연산자 갖다쓰면 된다 했다. 근데 가끔은 typeof 키워드로 할 수 없는 Narrowing 상황들이 있다.

null & undefined -> 타입체크하는 경우 매우 잦음

그 전에 테그닉 하나만 배우고 가자.

실제 코드를 짤 때 'undefined'라는 타입을 체크하는 경우가 엄청 많다. 예로 들어서 함수를 하나 만들었다 하자. 이 함수는 string 혹은 undefined다.

function 함수(a :string | undefined){
    
}

이때 a를 그냥 쓰면 안된다. if 문을 써서 a가 string인지, undefined인지 체크해야 한다. 근데 이게 귀찮아서 대신 typeof 연산자를 쓴다 했다.

function 함수(a :string | undefined){
	if(typeof a === 'string'){
        
    } else {
        
    }
}

이렇게 하면 undefined 경우를 체크할 수 있다. 근데 이걸 하나로 줄일 수 있다.

1. && 연산자로 null & undefined 타입체크하기

if (a && typeof a === 'string') { ... }

이렇게 하면 이제 undefined인지도 한 번에 Narrowing할 수 있다.

case 1. a가 undefined면,

➡️ 조건식 전체가 undefined가 남는다. 그래서 if문 조건식이 만족하지 않아서 실행되지 않는다.

case2. a가 string 타입이면

➡️ 우측에 있는 조건식이 실행된다. 조건식(typeof a === 'string')을 실행하면 true가 남는다.

즉,

  • a가 undefined면 if문 실행 X
  • a가 string이면 if문 실행 O

이것도 일종의 Narrowing으로 볼 수 있다. 일케 하면 undefined와 null 타입도 체크할 수 있다. if문 쓰기 귀찮으면 이거 쓰자.

근데 이게 익숙하지 않다? 하면 안쓰는 것도 좋다. 차라리 if/else 쓰는게 명확하고 좋을지도.

in 키워드로 objec narrowing 가능

typeof 연산자는 number, string, boolean, object 이런 식으로만 판정가능

Fish | Bird 타입만 들어올 수 있는 함수가 있다.

type FIsh = {swim :string}
type Bird = {fly :string}

function 함수(animal :Fish | Bird){
    animal.swim // Error!
}

animal 변수를 조작하려고 animal.swim을 치면 에러가 난다. 못한다. 왜냐면 animal 변수는 아직 애매해서 swim을 포함할 수 없을 수도 있다. 그래서 Narrowing을 해줘야 한다.

type FIsh = {swim :string}
type Bird = {fly :string}

function 함수(animal :Fish | Bird){
    if(typeof animal === Fish) {
        animal.swim // Error!
    }
}

Fish라고 typeof 연산자를 해주면 에러가 발생한다. 왜냐하면 typeof 연산자는 number, string, boolean, object, bigint, function, symbol, undefined, ... 등 자동완성되는 타입들만 판정할 수 있기 때문이다.

이때 쓸 수 있는게 in 키워드다!서로 배타적인 속성을 가지고 있는 타입들이 있다. Fish 타입은 swim 속성명을 가지고 있고, Bird 타입은 fly 속성명을 가지고 있다. 서로 가진 속성명이 다르다.

그런 오브젝트를 구분하고 싶을 때 in 키워드를 쓰면 된다.

속성명 in 오브젝트자료

왼쪽에 있는 속성명이 오른쪽에 있는 오브젝트에 들어가 있는지 알 수 있다. 이걸 코드에 응용해보면,

type FIsh = {swim :string}
type Bird = {fly :string}

function 함수(animal :Fish | Bird){
    if('swim' in animal) { // Fish 타입인지 검사가능
        animal.swim;
    }
}

유사하게 fly 속성으로 'Bird' 타입인지 검사 가능하다.

⭐서로 가진 속성명이 다르다면 in 써보자!

3. instanceof 연산자로 object narrowing 가능

오브젝트 instanceof 부모class

왼쪽 오브젝트의 부모가 오른쪽 부모가 맞는지 true/false 반환된다.

**object 두개가 비슷하면 부모 class가 누군지 물어봐서 narrowing 가능하다.**

예제를 보자면 이렇게.

let 날짜 = new Date();
if (날짜 instanceof Date){
    ...
}

4. object 타입마다 literal type 만들어두면 narrowing 편리해짐

object 타입이 둘다 비슷하게 생겼는데 이런 경우엔 narrowing을 어떻게 하나?

type Car = {
    wheel : '4개',
    color : string
}
type Bike = {
    wheel : '2개',
    color : string
}

function 함수(x :Car | Bike){
    if(x가 Car 타입이냐?)
}

in 키워드? instanceof? 못하지!

  • in 쓰려면 배타적인 속성을 찾아야한다. 근데 둘이 속성명이 같다.
  • instanceof? 둘 다 부모가 없다. 그래서 쓸 수 없다.

이렇게 비슷한 오브젝트 두개 타입을 구분해야 한다? 근데 애초에 타입을 하나로 합치지 왜 비슷한 타입을 따로 만들었나.. 근데 굳이굳이 구분을 해야한다면.

**비슷한 object 타입일 경우, literal type을 강제로 만들어두면 나중에 도움된다.**

wheel은 무조건 unique한 string이 들어올 수 있다. 이 literal type을 이용하면 구분할 수 있다. 이것도 unique해서 배타적이기 때문.

이때 if문을 이렇게 작성할 수 있겠다.

function 함수(x :Car | Bike){
    if(x.wheel === '4개'){ // 이 경우, x변수는 Car 타입임
        console.log('x는 Car타입이에요')
    }
}

⭐비슷한 object 타입이 많다! 그러면 literal type(고정된 값)을 넣어보자

Recap

논리적으로 이 타입인지 특정지을 수 있으면 narrowing으로 인정해줌. 자신있게 해보자.

반응형