타입의 호환성
기본 타입의 호환성
객체 타입의 호환성
함수 타입의 호환성
클래스의 호환성
제네릭의 호환성
열거형의 호환성
기본 타입의 호환성
두 가지 다른 타입의 A와 B에 대해, 모든 A 타입의 값을 B 타입의 값으로도 취급할 수 있는가?
할당 가능
type OneDigitOdd = 1 | 3 | 5 | 7 | 9;
const three: OneDigitOdd = 3;
const num: number = three;
할당 불가능
const four: number = 4;
const oneDigitOdd: OneDigitOdd = four;
// error TS2322: Type 'number' is not assignable to type 'OneDigitOdd'.
객체 타입의 호환성
타입 A와 B에 대해, A가 B에 할당 가능하려면 아래의 두 기준을 만족해야한다.
1. B 타입의 모든 필수 멤버에 대해, A에도 같은 이름의 멤버가 존재하는가?
2. B타입과 A타입에 동시에 존재하는 멤버
interface User {
name: string;
height: number;
}
interface Pet {
name: string;
species?: string;
}
const user: User = { name: '안희종', height: 176 };
const puppy: Pet = { name: '해피' };
const pet2: Pet = user; // ??
const user2: User = pet; // ??
User는 Pet에 할당이 가능하다. name 을 동일하게 가지고 있기 때문이다.
Pet은 User에 할당하지 못한다. height의 값이 없기 때문이다.
구조적 타입 시스템 structural type system
두 타입의 구조만을 비교하여 호환성을 결정하며, 어떤 타입이 다른 타입이 갖는 멤버를 전부 가지고 있으면 호환이 가능하다. 이렇게 동작하는것을 구조적 타입 시스템이라고 한다.
C++, JAVA 등의 언어가 채택한 노미널 타입 시스템은 특정 키워드를 통해 서로 호환 가능하다고 명시적으로 표현 된 타입 간의 할당만을 허용한다
노미널 타입 시스템 예시
class Foo {
method(input: string): number { ... }
}
class Bar {
method(input: string): number { ... }
}
let foo: Foo = new Bar(); // ERROR!!
객체 리터럴과 과잉 속성 검사 (excess property checking)
객체 리터럴이기 때문에 아래의 예시에서 에러가 발생된다고 한다.
객체 리터럴을 할당하는 경우에는 그 리터럴이 알려지지 않은 속성, 즉 할당 받는 타입에 존재하지 않는 속성을 포함한다면 타입 에러가 발생한다.
interface Color {
R: number;
G: number;
B: number;
}
const white: Color = {
R: 255,
G: 255,
B: 255,
A: 1
};
error TS2322: Type '{ R: number; G: number; B: number; A: number; }' is not assignable to type 'Color'.
Object literal may only specify known properties, and 'A' does not exist in type 'Color'.
객체 리터럴만 알려지지 않은 속성은 없는지 추가적으로 시행하는것을 과잉 속성 검사 라고 부른다.
interface Color {
R: number;
G: number;
B: number;
}
const someColor = {
R: 255,
G: 255,
B: 255,
A: 1
};
const white: Color = someColor;
// 정상적으로 동작
과잉 속성 검사가 존재하는 이유
프로그래머의 실수를 막기 위해 존재하며, 어떤 타입의 값에 객체 리터럴을 직접 할당하는 경우, 만약 타입에 정의되지 않은 멤버는 오타 등의 실수로 인해 오류가 발생될 활률이 높다고 가정하기 때문에 객체 리터럴에서는 정확하게 타입을 확인한다고 한다.
함수 타입의 호환성
sum 은 multiply에 할당 가능하다
1. 모든 매개변수의 타입은 number 로 서로 할당 가능하다.
2. 반환 값이 number 로 동일하기 떄문에 서로 할당 가능하다.
type Sum = (sumFirst: number, sumSecond: number) => number;
type Multiply = (mulFirst: number, mulSecond: number) => number;
const sum: Sum (sumFirst: number, sumSecond: number) => {
return sumFirst + sumSecond;
};
const multiply: Multiply = sum; // ok
할당 불가능
g에서 dogProp 에 접근하려면 에러를 발생할 수 있으므로, 할당이 불가능하다.
interface Animal { animalProp: string };
interface Dog extends Animal { dogProp: number };
let f = (animal: Animal) => animal.animalProp;
let g = (dog: Dog) => { doSomething(dog.dogProp) };
f = g;
매개변수가 다른 경우
type Login = (id: string) => Response<Data>;
type LoginWithToken = (id: string, token: string) => Response<Data>;
할당하는 함수의 매개변수 수가 더 많은 경우 할당 불가능
const loginWithToken: LoginWithToken = (id: string, token: string) => { /* ... */ };
const login: Login = loginWithToken;
할당받는 함수의 매개변수 수가 더 많은 경우 할당 가능
const login: Login = (id: string) => { /* ... */ };
const loginWithToken: LoginWithToken = login;
클래스의 호환성
스태틱 멤버 및 생성자는 호환성 비교에 영향을 주지 않는다. Animal, Size 두 클래스의 생성자 타입 시그니처가 다름에도 오류 없이 할당이 가능하다.
class Animal {
feet: number;
constructor(name: string, numFeet: number) { }
}
class Size {
feet: number;
constructor(numFeet: number) { }
}
let a: Animal;
let s: Size;
a = s; // ok
s = a; // ok
private 및 protected 멤버
다른 클래스에서 정의된 private 멤버는 할당이 불가능하다.
class FacebookUser {
constructor (id: string, private password: string) {}
}
class TwitterUser {
constructor (id: string, private password: string) {}
}
let twitterUser: TwitterUser;
let facebookUser: FacebookUser;
twitterUser = facebookUser;
// error TS2322: Type 'FacebookUser' is not assignable to type 'TwitterUser'.
// Types have separate declarations of a private property 'password'.
제네릭의 호환성
NotEmpty의 number, string의 타입이 다르기 때문에 할당이 불가능하다.
interface NotEmpty<T> {
data: T;
}
let x: NotEmpty<number>;
let y: NotEmpty<string>;
y = x;
// 에러 발생
어떤 타입인지 알려지지 않은 타입 변수가 있는경우
아래와 같은 경우 타입 변수를 모두 any 타입으로 대체하고 호환성을 판단하기 때문에 할당을 허용한다
const identity = function<T>(x: T): T {
// ...
};
const reverse = function<U>(y: U): U {
// ...
};
identity = reverse;
//할당 허용
열거형의 호환성
다른 열거형으로부터 유래된 값끼리는 호환되지 않는다.
enum Status { Ready, Waiting }
enum Color { Red, Blue, Green }
let status: Status = Status.Ready;
status = Color.Green; // error
참고
https://ahnheejong.gitbook.io/ts-for-jsdev/05-type-compatibility/intro
5.0 들어가며 - ts-for-jsdev
이 장에서는 기본 타입에서부터 시작해 제너릭, 클래스를 비롯한 복잡한 타입들까지, 타입의 호환성 비교가 어떻게 이루어지는지 하나씩, 구체적으로 알아볼 것이다. 타입 호환성을 판단하는
ahnheejong.gitbook.io
'TypeScript' 카테고리의 다른 글
[Typescript] 4. ts-for-jsdev 타입 시스템 심화 (0) | 2023.10.06 |
---|---|
[Typescript] 2. ts-for-jsdev 인터페이스와 클래스 공부 (0) | 2023.09.30 |
[Typescript] 1. ts-for-jsdev 타입스크립트 기초 문법 공부 (0) | 2023.09.28 |