타입스크립트 런타임 타입 체크

김윤진·2022년 3월 16일
1

TypeScript

목록 보기
1/2

타입스크립트는 런타임에 타입 체크가 불가능하다

interface Student {
 id: number;
}

interface Lee extends Student {
 name: string; 
}
type Person = Student | Lee;

function setStudent(arg: Person) {
 if (arg instanceof Lee) {
   // Person 형식에 name 속성은 없다
   return arg.name; 
 }
}

instanceof 체크는 런타임에 일어나지만 Lee는 타입이기 때문에 런타임 시점에 어떤 역할도 할 수 없다

타입스크립트의 타입은 제거기능이 있다
자바스크립트로 컴파일되는 과정에서 모든 타입, 인터페이스, 타입 구문은 다 제거된다

arg의 타입을 명확하게 하고 싶다면 런타임에 타입 정보를 유지할 필요가 있다
name 속성이 존재하는지 체크하는 것이다

interface Student {
 id: number;
}

interface Lee extends Student {
 name: string; 
}
type Person = Student | Lee;

function setStudent(arg: Person) {
 if ('name' in arg) {
   return arg.name; 
 }
}

속성 체크는 런타임에 접근 가능한 값에만 관련되지만 타입 체크 약시 arg의 타입을 Lee로 보정해주기 때문에 오류가 사리진다


타입 정보를 유지하는 다른 방법으로는 런타임에 접근 가능한 타입 정보를 명시적으로 저장하는 태그 기법이다
interface Student {
 kind: 'student';
 id: number;
}

interface Lee extends Student {
 kind: 'lee';
 name: string; 
}
type Person = Student | Lee;

function setStudent(arg: Person) {
 if (arg.kind === 'student') {
   arg; // arg: Lee
   return arg.name; 
 }
}

여기서 Person 타입은 태그된 유니온이다
태그 기법은 런타임에 타입 정보를 쉽게 유지할 수 있다


타입(런타임에 접근 불가)과 값(런타임에 접ㅂ근 가능)을 둘 다 사용하는 기법도 있다
타입을 클래스로 만드는 것이다

class Student {
  constructor(public id: number) {}
}

class Lee extends Student {
  constructor(public name: string) {
   	super(id); 
  }
}
type Person = Student | Lee;

function setStudent(arg: Person) {
 if (arg instanceof Lee) {
   arg; // arg: Lee
   return arg.name; 
 }
}

인터페이스는 타입으로만 사용 가능하지만
클래스는 타입과 값으로 모두 사용할 수 있어 오류가 없다

type Person = Student | Lee 에서 Lee는 타입으로 참조되지만
arg instanceof Lee 에서는 값으로 참조된다


타입스크립트는 타입과 런타임의 동작이 무관하기 때문에 함수 오버로딩은 불가능하다
타입스크립트는 함수 오버로딩을 지원하기는 하지만 타입수준에서만 가능하다

function foo(a: string, b: string): string;
function foo(a: number, b: number): number;

function foo(a: any, b: any) {
  return a + b;
}
const num = add(1, 1); // 타입은 number
const str = add('1', '1'); // 타입은 string

오버로딩을 하기위해서는 인자의 타입을 any로 지정해야 한다
foo에 대한 앞의 선언문은 타입 정보를 제공하기만 한다
두 선언문은 타입스크립트가 컴파일되면서 제거되어 구현체만 남게된다
굳이 쓸 필요는 없을 것 같다

0개의 댓글