궁금한게 많은 열아홉

타입 가드

Typescript에서 변수의 타입을 좁히는데 사용되는 메커니즘

사용자 정의 타입가드

타입 서술어 사용

function isFish(pet: Fish | Bird): pet is Fish {
	return (pet as Fish).swim !== undefined;	
}

 

  1. 보통 타입 가드는 isFish 와 같이 is를 많이 붙인다.
  2. is 는 타입 가드에서 사용되는 키워드이다.
  3. pet is Fish 파라미터(pet)가 실재 해당 타입(Fish)인지 구분하는 키워드이다.
  4. return (target as Developer).swim !== undefined 는 pet에 swim 프로퍼티가 있으면 Fish 타입으로 취급한다.
interface Bird {
    fly: () => void;
    layEggs: () => void;
}

interface Fish {
    swim: () => void;
    layEggs: () => void;
}

function getSmallPet(): Fish | Bird {
    return { 
      fly: function() {},
      layEggs: function() {} 
    };
}

function isFish(pet: Fish | Bird): pet is Fish {
	return (pet as Fish).swim !== undefined;	
}

let pet = getSmallPet();

if(isFish(pet)) {
	pet.swim();  // Fish 
} else {
	pet.fly();   // Bird
}

 

pet 이 if 문 안에서 Fish 라는 것을 알고 있고, else 문 안에서는 Fish 타입이 아니라는 걸 알고 있으므로 Bird 를 반드시 가지고 있다.

 

in연산자 사용

in 연산자는 타입을 좁히는 표현으로 작용

 

n in x 표현에서 n은 문자열 혹은 리터럴 타입이고, x 는 유니언 타입

function move(pet: Fish | Bird) {
	if('swim' in pet) {
    	return pet.swim();
    }
  
  	return pet.fly();
}

 

typeof 타입가드

값이 원시 타입인지 아닌지 확인하는 함수를 정의할 수 있다.

function isNumber(x: any): x is number {
    return typeof x === "number";
}

function isString(x: any): x is string {
    return typeof x === "string";
}

 

그러나 원시타입 확인을 위해 모든 함수를 작성하는 건 번거로운 일이다. 다행인 사실은, 타입스크립트는 typeof를 타입가드로 인식한다.

function valueFunc(value: number | string) {
  // typeof 타입 가드로 사용할 수 있다.
  if(typeof value === 'string') {
  	return value.length; // string
  }
  return value; // number
}

 

instanceof 타입 가드

생성자 함수를 사용해 타입을 좁힐 수 있다.

interface Person {
	// name: string;
  	getName: () => string;
} 

class Employee implements Person {
	constructor(private name: string) { }
  	getName() {
    	return this.name;
    }
}

class Employer implements Person {
	constructor(private name: string) { }
  	getName() {
    	return this.name;
    }
}

function getClass(isEmployee: boolean = true) {
	return isEmployee ? 
      new Employee('Employee') 
    : new Employer('Employer');
}

let person: Person = getClass(true);

if(person instanceof Employee) { 
	person; // person 타입은 Employee
}

if(person instanceof Employer) { 
	person; // person 타입은 Employer
}

 

널러블 타입

타입스크립트에서 null과 undefined는 모든 타입에서 유효한 값이다. 즉, 방지하고 싶어도 어떤 타입에 할당되는 것을 방지할 수 없다.

 

이 문제는 --strictNullChecks플래그로 해결 가능하다. 변수를 선언할 시에 자동으로 null이나 undefined를 포함하지 않고, 유니온 타입을 사용해 명시적으로 포함할 수 있다.

 

// --strictNullChecks 플래그로 null을 포함하지 못하게 한다.
let str = "str";
str = null; // 오류

// 유니온 타입을 사용해서 명시적으로 null을 포함한다.
let str2: string | null = "atr2";
str2 = null;

선택적 매개변수 & 프로퍼티

--strictNullChecks를 적용할 때 선택적 매개변수에 | undefined를 자동으로 추가한다.

// 선택적 매개변수
function fun(x: number, y?: number) {
	return x + (y || 0);
}

fun(1, 2);
fun(1);
fun(1, undefined); // | undefined가 자동으로 추가되므로 오류가 발생하지 않는다.
fun(1, null); // 오류, 'null' 은 number | undefined에 할당할 수 없다.

// 선택적 프로퍼티도 마찬가지
class C {
	a: number;
  	b?: number;
}

let c = new C();
c.a = 1;
c.b = 2;
c.b = undefined; // | undefined가 자동으로 추가되므로 오류가 발생하지 않는다.
c.b = null; // 오류, 'null' 은 number | undefined에 할당할 수 없다.

 

profile

궁금한게 많은 열아홉

@jjin502

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!