목차
- DRY: 같은 코드를 반복하지 마라
- 타입에서 중복이 더 흔한 이유 중 하나는 공유된 패턴을 제거하는 메커니즘이 기존 코드에서 하던 것과 비교해 덜 익숙하기 때문
- 반복을 줄이는 가장 간단한 방법 → 타입에 이름을 붙이는 것
- 중복된 타입은 종종 문법에 의해서 가려지기도 함
확장해서 반복 제거하는 방법
- 두 인터페이스가 필드의 부분 집합을 공유한다면, 공통 필드만 골라서 기반 클래스로 분리 가능
interface Person {
firstNmae: string;
lastName: sring;
}
interface PersonWithBirthDate extends Person {
birth: Date;
}
interface PersonWithAge extends Person {
age: number;
}
- 이미 존재하는 타입을 확장하는 경우 → 인터섹션 연산자(&) //흔하지 않음
- 유니온 타입에 속성을 추가할 때 유용함(유니온 타입은 확장 X)
type PersonWithBirthDate = Person & {birth: Date};
- State를 인덱싱하여 속성의 타입에서 중복을 제거하는 방법
- interface State { userId: string; pageTitle: string; recenFiles: string[]; pageContents: string; } type TopNavState = { userId: State["userId"]; pageTitle: State["pageTitle"]; recentFiles: State["recentFiles"]; }
매핑된 타입을 사용하는 방법
- 매핑된 타입은 배열의 필드를 루프 도는 것과 같은 방식
- 이 패턴은 Pick이라고 표준 라이브러리에 있음.
type TopNavState = {
[k in "userId" | "pageTitle" | "recenFiles"]: State[k]
};
Pick 사용하는 방법
- Pick은 제네릭 타입. Pick을 사용하는 것은 함수를 호출하는 것과 마찬가지
- Pick은 T와 K 두가지 타입을 받아서 결과를 타입을 반환
type Pick<T, K> = {[k in K]: T[k]}; //기본형
type TopNavState = Pick<State, "userId" | "pageTitle" | "recenFiles">;
태그된 유니온의 타입 중복 제거
- 유니온 인덱싱
- ActionType은 Pick을 사용하여 얻게 되는, type 속성을 가지는 인터페이스와 다름
interface SaveAction {
type: "save";
...
}
interface LoadAction {
type: "load";
...
}
type Action = SaveAction | LoadAction;
type ActionType = Action["type"];/// === type a = "save" | "load";
선택적 필드에 대한 중복 제거
- 매핑된 타입과 keyof을 사용
- 이 패턴은 Partical이고 표준 라이브러리에 있음
interface Options {
width: number;
height: number;
color: string;
label: string;
}
type OptionsUpdate = {[k in keyof Options]?: Options[k]};
- keyof은 타입을 받아서 속성 타입의 유니온을 반환
type OptionsKeys = keyof Options; // 타입이 "width"|"height"|"color"|"label"
Partical 사용하는 방법
- 특정 타입의 부분 집합을 만족하는 타입을 정의할 수 있다.
type Partial<T> = {[p in keyof T]? = T[p]}; //기본형(필수를 옵셔널로)
type Partial<T> = {[p in keyof T]-? = T[p]}; // 옵셔널을 필수로 만들기
function updateOptionItem(OptionsUpdate: Partial<Options>) { ... }
값의 형태에 해당하는 타입을 정의 하고 싶을 때
- 여기에서 typeof는 런타임 연산자가 아닌 타입스크립트 단계에서 연산된다
- 훨씬 더 정확하게 타입을 표현
- 사용 시 선언의 순서에 주의해야
- 타입 정의를 먼저 하고 값이 그 타입에 할당 가능하다고 선언.
const INIT_OPTIONS = {
width: 60;
height: 40;
color: "#00FF00";
label: "VGA"
}
type Options = typeof INIT_OPTIONS;
함수나 메서드의 반환 값에 명명된 타입을 만들고 싶을 때
- 조건부 타입이 필요함 → ReturnType 제너릭 사용(표준 라이브러리에 있음)
- ReturnType은 함수의 값이 아니라 타입에 적용된다.
- 적용 대상이 값인지, 타입인지 정확하게 구분&처리
function getUserInfo(userId: string) {
...
return { userId, name, age, height, weight}; //이걸 타입으로 만들고 싶음
}
type UserInfo = ReturnType<typeof getUserInfo>;
제너릭 타입
- 제너릭 타입은 타입을 위한 함수
- 제너릭 타입에서 매개변수를 제한할 수 있는 방법이 필요함
- 제너릭 타입에서 매개변수를 제한할 수 있는 방법은 extends를 사용하는 것
- 타입스크립트가 제너릭 매개변수의 타입을 추론하게 하기 위해, 함수를 작성할 때 신중하게 타입을 고려해야함
- Pick함수에서 K는 범위가 너무 넓음
- K는 실제로 T의 키의 부분집합(keyof T)가 되어야
- 타입이 값의 집합이라는 관점에서 생각하면 extends가 확장이 아닌 부분집합
type Pick<T, K> = {[k in K]: T[k]};
->
type Pick<T, K extends keyof T> = {[k in K]: T[k]};
→ 이 모든 과정의 목표는 유효한 프로그램은 통과시키고 무효한 프로그램에는 오류를 발생시키는 것.
'책 정리 > 이펙티브 타입스크립트' 카테고리의 다른 글
아이템 41 any의 진화를 이해하기 (0) | 2023.07.26 |
---|---|
아이템 40 함수 안으로 타입 단언문 감추기 (0) | 2023.07.26 |
아이템 26 타입 추론에 문맥이 어떻게 사용되는지 이해하기 (0) | 2023.07.26 |
아이템 25 비동기 코드에는 콜백 대신 async 함수 사용하기 (0) | 2023.07.26 |
아이템 13 타입과 인터페이스의 차이점 알기 (0) | 2023.07.26 |
- DRY: 같은 코드를 반복하지 마라
- 타입에서 중복이 더 흔한 이유 중 하나는 공유된 패턴을 제거하는 메커니즘이 기존 코드에서 하던 것과 비교해 덜 익숙하기 때문
- 반복을 줄이는 가장 간단한 방법 → 타입에 이름을 붙이는 것
- 중복된 타입은 종종 문법에 의해서 가려지기도 함
확장해서 반복 제거하는 방법
- 두 인터페이스가 필드의 부분 집합을 공유한다면, 공통 필드만 골라서 기반 클래스로 분리 가능
interface Person {
firstNmae: string;
lastName: sring;
}
interface PersonWithBirthDate extends Person {
birth: Date;
}
interface PersonWithAge extends Person {
age: number;
}
- 이미 존재하는 타입을 확장하는 경우 → 인터섹션 연산자(&) //흔하지 않음
- 유니온 타입에 속성을 추가할 때 유용함(유니온 타입은 확장 X)
type PersonWithBirthDate = Person & {birth: Date};
- State를 인덱싱하여 속성의 타입에서 중복을 제거하는 방법
- interface State { userId: string; pageTitle: string; recenFiles: string[]; pageContents: string; } type TopNavState = { userId: State["userId"]; pageTitle: State["pageTitle"]; recentFiles: State["recentFiles"]; }
매핑된 타입을 사용하는 방법
- 매핑된 타입은 배열의 필드를 루프 도는 것과 같은 방식
- 이 패턴은 Pick이라고 표준 라이브러리에 있음.
type TopNavState = {
[k in "userId" | "pageTitle" | "recenFiles"]: State[k]
};
Pick 사용하는 방법
- Pick은 제네릭 타입. Pick을 사용하는 것은 함수를 호출하는 것과 마찬가지
- Pick은 T와 K 두가지 타입을 받아서 결과를 타입을 반환
type Pick<T, K> = {[k in K]: T[k]}; //기본형
type TopNavState = Pick<State, "userId" | "pageTitle" | "recenFiles">;
태그된 유니온의 타입 중복 제거
- 유니온 인덱싱
- ActionType은 Pick을 사용하여 얻게 되는, type 속성을 가지는 인터페이스와 다름
interface SaveAction {
type: "save";
...
}
interface LoadAction {
type: "load";
...
}
type Action = SaveAction | LoadAction;
type ActionType = Action["type"];/// === type a = "save" | "load";
선택적 필드에 대한 중복 제거
- 매핑된 타입과 keyof을 사용
- 이 패턴은 Partical이고 표준 라이브러리에 있음
interface Options {
width: number;
height: number;
color: string;
label: string;
}
type OptionsUpdate = {[k in keyof Options]?: Options[k]};
- keyof은 타입을 받아서 속성 타입의 유니온을 반환
type OptionsKeys = keyof Options; // 타입이 "width"|"height"|"color"|"label"
Partical 사용하는 방법
- 특정 타입의 부분 집합을 만족하는 타입을 정의할 수 있다.
type Partial<T> = {[p in keyof T]? = T[p]}; //기본형(필수를 옵셔널로)
type Partial<T> = {[p in keyof T]-? = T[p]}; // 옵셔널을 필수로 만들기
function updateOptionItem(OptionsUpdate: Partial<Options>) { ... }
값의 형태에 해당하는 타입을 정의 하고 싶을 때
- 여기에서 typeof는 런타임 연산자가 아닌 타입스크립트 단계에서 연산된다
- 훨씬 더 정확하게 타입을 표현
- 사용 시 선언의 순서에 주의해야
- 타입 정의를 먼저 하고 값이 그 타입에 할당 가능하다고 선언.
const INIT_OPTIONS = {
width: 60;
height: 40;
color: "#00FF00";
label: "VGA"
}
type Options = typeof INIT_OPTIONS;
함수나 메서드의 반환 값에 명명된 타입을 만들고 싶을 때
- 조건부 타입이 필요함 → ReturnType 제너릭 사용(표준 라이브러리에 있음)
- ReturnType은 함수의 값이 아니라 타입에 적용된다.
- 적용 대상이 값인지, 타입인지 정확하게 구분&처리
function getUserInfo(userId: string) {
...
return { userId, name, age, height, weight}; //이걸 타입으로 만들고 싶음
}
type UserInfo = ReturnType<typeof getUserInfo>;
제너릭 타입
- 제너릭 타입은 타입을 위한 함수
- 제너릭 타입에서 매개변수를 제한할 수 있는 방법이 필요함
- 제너릭 타입에서 매개변수를 제한할 수 있는 방법은 extends를 사용하는 것
- 타입스크립트가 제너릭 매개변수의 타입을 추론하게 하기 위해, 함수를 작성할 때 신중하게 타입을 고려해야함
- Pick함수에서 K는 범위가 너무 넓음
- K는 실제로 T의 키의 부분집합(keyof T)가 되어야
- 타입이 값의 집합이라는 관점에서 생각하면 extends가 확장이 아닌 부분집합
type Pick<T, K> = {[k in K]: T[k]};
->
type Pick<T, K extends keyof T> = {[k in K]: T[k]};
→ 이 모든 과정의 목표는 유효한 프로그램은 통과시키고 무효한 프로그램에는 오류를 발생시키는 것.
'책 정리 > 이펙티브 타입스크립트' 카테고리의 다른 글
아이템 41 any의 진화를 이해하기 (0) | 2023.07.26 |
---|---|
아이템 40 함수 안으로 타입 단언문 감추기 (0) | 2023.07.26 |
아이템 26 타입 추론에 문맥이 어떻게 사용되는지 이해하기 (0) | 2023.07.26 |
아이템 25 비동기 코드에는 콜백 대신 async 함수 사용하기 (0) | 2023.07.26 |
아이템 13 타입과 인터페이스의 차이점 알기 (0) | 2023.07.26 |