타입스크립트는 런타임에 타입 체크가 불가능하다
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에 대한 앞의 선언문은 타입 정보를 제공하기만 한다
두 선언문은 타입스크립트가 컴파일되면서 제거되어 구현체만 남게된다
굳이 쓸 필요는 없을 것 같다