Typescript 4.5의 새 기능
- Typescript 4.5에서 추가된 기능들을 공부하며 정리해보았다. (모든 추가 사항을 정리한 것은 아님.)
새 유틸리티 타입, Awaited
1
2
3
4
5
6
7
8
| // A = string
type A = Awaited<Promise<string>>;
// B = number
type B = Awaited<Promise<Promise<number>>>;
// C = boolean | number
type C = Awaited<boolean | Promise<number>>;
|
타입스크립트 4.5에 Awaited
라는 유틸리티 타입이 추가되었다.
Awaited
는 재귀적으로 프라미스일 수 있는 값들을 Unwrap 한 타입을 만든다.
예를 들어 기존의 타입스크립트에선
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| declare function MaybePromise<T>(value: T): T | Promise<T> | PromiseLike<T>;
async function doSomething(): Promise<[number, number]> {
const result = await Promise.all([
MaybePromise(100),
MaybePromise(200)
]);
// Error!
//
// [number | Promise<100>, number | Promise<200>]
//
// is not assignable to type
//
// [number, number]
return result;
}
|
에러 메시지에 나오듯이 위 함수 doSomething
은 [number | Promise<100>, number | Promise<200>]
를 [number, number]
에 대입할 수 없다는 컴파일 에러가 난다.
기존의 타입스크립트로 doSomething
을 작성하기 위해선, 아래처럼 리턴 타입을 복잡하게 명시해야 한다.
1
2
3
| async function doSomething(): Promise<[number | Promise<number>, number | Promise<number>]> {
...
}
|
Awaited
를 사용하면, 아래 함수를 보다 직관적으로 정의할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
| declare function MaybePromise<T>(value: T): T | Promise<T> | PromiseLike<T>;
async function doSomething(): Awaited<Promise<[number, number]>> {
const result = await Promise.all([
MaybePromise(100),
MaybePromise(200)
]);
// OK
return result;
}
|
node_modules에서의 lib 지원
Template string을 통한 타입 판별 (Discriminants) 지원
기존의 타입스크립트에서 다음 코드는 아래와 같은 컴파일 에러가 난다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| export interface Success {
type: `${string}Success`;
body: string;
}
export interface Error {
type: `${string}Error`;
message: string;
}
export function handler(r: Success | Error) {
if (r.type === "HttpSuccess") {
// Property 'body' does not exist on type 'Success | Error'.
let token = r.body;
}
}
|
타입스크립트 4.5 이후부터는 r.type
이 Success
로 끝나는 string 이라는 것을 검사한 이후엔, 자동으로 Success 타입으로 추론되어, 컴파일 에러가 없어진다.
Conditional Types의 꼬리 재귀 제거
import 문 생략 비활성화
기존의 타입스크립트에서 아래 코드를 컴파일 하면, Animal을 사용하고 있는 변수로 탐지하지 못해, 해당 import 구문을 제거해, 개발자의 의도대로 동작하지 않는다.
1
2
3
| import { Animal } from "./animal.js";
eval("console.log(new Animal().isDangerous())");
|
4.5 이후엔 preserveValueImports
플래그를 사용해 타입스크립트의 이런 동작을 변경할 수 있다.
타입 import 구문 확장 (type Modifiers on Import Names)
아래 코드는 기존 타입스크립트에서 에러를 낸다.
BaseType
은 타입이고, someFunc
은 함수여서 ts-loader
등의 라이브러리들은 컴파일 타임에 어떤 value가 남겨져야 하는지 알 수 없어 에러를 낸다.
1
2
3
4
5
6
| // Which of these is a value that should be preserved? tsc knows, but `ts.transpileModule`,
// ts-loader, esbuild, etc. don't, so `isolatedModules` issues an error.
import { someFunc, BaseType } from "./some-module.js";
// ^^^^^^^^
// Error: 'BaseType' is a type and must be imported using a type-only import
// when 'preserveValueImports' and 'isolatedModules' are both enabled.```
|
위 statement는 기존의 타입스크립트에서 아래처럼 "./some-module.js"
를 중복해 써야 했다.
1
2
| import type { BaseType } from "./some-module.js";
import { someFunc } from "./some-module.js";
|
4.5 이후에선 아래처럼 한 번에 가져올 수 있다.
1
2
3
4
5
6
7
| import { someFunc, type BaseType } from "./some-module.js";
export class Thing implements BaseType {
someMethod() {
someFunc();
}
}
|
위처럼 한 번에 가져와도 알아서 BaseType
은 컴파일 타임에 지워지고, someFunc
은 남는 것이 보장된다.
예를 들어 위 코드는 아래처럼 컴파일 된다.
1
2
3
4
5
6
7
| import { someFunc } from "./some-module.js";
export class Thing {
someMethod() {
someFunc();
}
}
|
private 변수 존재 체크
타입스크립트 4.5 이후부턴 해당 객체의 private 변수가 존재하는지 in
operator를 사용해 확인할 수 있다.
예를 들어 아래와 같은 코드를 작성할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
| class Person {
#name: string;
constructor(name: string) {
this.#name = name;
}
equals(other: unknown) {
return other &&
typeof other === "object" &&
#name in other && // <- this is new!
this.#name === other.#name;
}
}
|
import 구문의 타입 assertions
타입스크립트 4.5에선, import 구문에서 가져온 값의 타입을 명시할 수 있다.
이것은 런타임에 import 구문이 해당 타입을 import 하는 것을 확실히 해 준다.
예를 들어 아래와 같은 코드 작성이 가능하다.
1
| import obj from "./something.json" assert { type: "json" };
|
1
2
3
| import obj from "./something.json" assert {
type: "fluffy bunny"
};
|
Dynamic import 구문 같은 경우 아래처럼 인자로 넘기는 식으로 쓸 수 있다.
1
2
3
| const obj = await import("./something.json", {
assert: { type: "json" }
})
|
원문