일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 |
- useAppDispatch
- Promise
- autosize
- CORS
- 결정 알고리즘
- 리터럴 타입
- 무한 스크롤
- 타입 좁히기
- TS
- 공변성
- MSA
- dfs
- React
- 태그된 유니온
- 투포인터
- SSR
- recoil
- Jest
- RTK Query
- 호이스팅
- tailwind
- map
- 인증/인가
- async/await
- 인터섹션
- 반공변성
- ESlint
- webpack
- app router
- CI/CD
- Today
- Total
짧은코딩
Utility Types 본문
Utility Types
https://www.typescriptlang.org/docs/handbook/utility-types.html
Documentation - Utility Types
Types which are globally included in TypeScript
www.typescriptlang.org
utility types는 ts가 미리 만들어 놓고 가져다 쓰면 되는 타입들이다. 객체를 조작할 때 도움이 많이 된다. 직접 만들 수도 있어야 한다.
예시
Partial
interface Profile {
name: string;
age: number;
married: boolean;
}
const ori: Profile = {
name: "ori",
age: 20,
married: false,
};
// 개인정보 보호를 위해 결혼 여부 제외하고 싶음
const newOri: Profile = {
name: "ori",
age: 20,
};
newOri는 개인정보 보호를 위해 결혼 여부를 제외하고 싶다. 하지만 이런식으로 코드를 짜면 에러가 난다.
interface Profile {
name: string;
age: number;
married: boolean;
}
const ori: Profile = {
name: "ori",
age: 20,
married: false,
};
// 개인정보 보호를 위해 결혼 여부 제외하고 싶음
const newOri: Partial<Profile> = {
name: "ori",
age: 20,
};
이렇게 하면 오류가 발생하지 않는다. 왜냐하면 partial은 Profile의 내용을 다 옵셔널로 만들어 주기 때문이다.
=> 하지만 partial이 그렇게 좋은 기능은 아니다. 왜냐하면 빈 객체가 생길수도 있기 때문이다.
-partial을 구현하기
interface Profile {
name: string;
age: number;
married: boolean;
}
type P<T> = {
// Profile의 name, age, married가 올 수 있다. 그리고 이것을 옵셔널로 만들 수 있다.
[key in keyof T]?: T[key];
}
const ori: Profile = {
name: "ori",
age: 20,
married: false,
};
// 개인정보 보호를 위해 결혼 여부 제외하고 싶음
const newOri: P<Profile> = {
name: "ori",
age: 20,
};
type P<T> 처럼 구현하면 된다. T[key]를 하면 타입도 가져올 수 있다. 이렇게 하나하나를 옵셔널로 만들어주면 된다.
Pick과 Omit
Pick
interface Profile {
name: string;
age: number;
married: boolean;
}
// 개인정보 보호를 위해 결혼 여부 제외하고 싶음
const newOri: Pick<Profile, "name" | "age"> = {
name: "ori",
age: 20,
};
뒤에 써 준 것만 뽑아서 사용할 수 있다.
-pick 만들기
interface Profile {
name: string;
age: number;
married: boolean;
}
type P<T, S extends keyof T> = {
[key in S]: T[key];
};
const ori: Profile = {
name: "ori",
age: 20,
married: false,
};
// 개인정보 보호를 위해 결혼 여부 제외하고 싶음
const newOri: P<Profile, "name" | "age"> = {
name: "ori",
age: 20,
};
type P 처럼 만들어야 하는데 S extends keyof T를 한 이유는 S와 T가 연결되어 있기 때문이다. 만약 저 예시에 Profile에 car 속성이 없는데 car 속성을 pick하면 안되니까 extends가 필요하다. 주의 할 점으로는 제네릭을 쓰면 제네릭의 제한 조건을 걸어두는 것이 제일 먼저이다.
Omit
interface Profile {
name: string;
age: number;
married: boolean;
}
// 개인정보 보호를 위해 결혼 여부 제외하고 싶음
const newOri: Omit<Profile, "married"> = {
name: "ori",
age: 20,
};
뒤에 써 준 것만 제외하고 사용할 수 있다.
-omit 만들기(밑에 Exclude 참고)
const newOri: Pick<Profile, Exclude<keyof Profile, "married">> = {
name: "ori",
age: 20,
};
omit은 Pick와 Exclude를 활용해서 만들 수 있다. 따라서 Exclude로 married를 제외하고 Pick로 선택하면 Omit을 만들 수 있다.
type O<T, S extends keyof any> = Pick<T, Exclude<keyof T, S>>;
// 개인정보 보호를 위해 결혼 여부 제외하고 싶음
const newOri: O<Profile, "married"> = {
name: "ori",
age: 20,
};
따라서 Omit은 Pick와 Exclude를 조합해서 만들 수 있다. S에 아무 값이나 오면 안되서 extends를 활용해 다른 어떤 것의 키 값만 오도록 했다.
Exculde와 Extract
Exclude
type Animal = 'Cat'|'Dog'|'Human';
type Mammal = Exclude<Animal, 'Human'>;
이렇게 하면 Mammal에는 Animal에서 Human을 제외한다.
따라서 이렇게 나오게 된다.
-Exclude
type Exclude<T, U> = T extends U ? never : T;
Exclude는 제외하는 거라서 T가 U의 부분 집합이면 naver로 없애버리고 아니면 포함한다.
Extract
type Animal = "Cat" | "Dog" | "Human";
type Human = Extract<Animal, "Cat" | "Dog">;
Extract는 뒤에 쓴 키를 추출해낸다. 따라서 Human의 타입은 Cat | Dog가 된다.
-Extract
type Extract<T, U> = T extends U ? T : never;
Extract는 포함하는 거니까 T가 U의 부분 집합이면 포함하고 아니면 없앤다.
=> Exclude와 Extract는 반대이다.
Required
interface Profile {
name?: string;
age?: number;
married?: boolean;
}
const newOri: Required<Profile> = {
name: "ori",
age: 20,
married: false,
};
Required는 옵셔널로 만들어진 키들에서 옵셔널을 제거하는 것이다.
-Required 만들기
interface Profile {
name?: string;
age?: number;
married?: boolean;
}
type R<T> = {
[key in keyof T]-?: T[key];
};
const newOri: R<Profile> = {
name: "ori",
age: 20,
married: false,
};
-?하면 옵셔널을 마이너스한다는 의미로 옵셔널이 사라진다.
Readonly
interface Profile {
name?: string;
age?: number;
married?: boolean;
}
const newOri: Readonly<Profile> = {
name: "ori",
age: 20,
married: false,
};
newOri.name = "babo";
Readonly 값을 사용하면 객체 값을 수정할 수 없다.
-Readonly 만들기
interface Profile {
name?: string;
age?: number;
married?: boolean;
}
type R<T> = {
readonly [key in keyof T]: T[key];
};
const newOri: R<Profile> = {
name: "ori",
age: 20,
married: false,
};
newOri.name = "babo";
이렇게 가져올 때 readonly를 붙이면 된다.
-readonly 제외
interface Profile {
readonly name?: string;
readonly age?: number;
readonly married?: boolean;
}
type R<T> = {
-readonly [key in keyof T]: T[key];
};
const newOri: R<Profile> = {
name: "ori",
age: 20,
married: false,
};
newOri.name = "babo";
-readonly하면 readonly를 제외하고 가져올 수 있다.
Record
interface Obj {
[key: string]: number;
}
const a: Obj = { a: 3, b: 5, c: 7 };
원래 객체를 만들기 위해서는 이렇게 해야한다.
const a: Record<string, number> = { a: 3, b: 5, c: 7 };
Record를 사용하면 바로 객체를 만들 수 있다.
-Record 만들기
type R<T extends keyof any, S> = {
[key in T]: S;
};
const a: Record<string, number> = { a: 3, b: 5, c: 7 };
객체의 키는 number, string, symbol만 올 수 있어서 이 제한 조건을 주기 위해 extends keyof any가 붙었다.
NonNullable
type A = string | null | undefined | boolean | number;
type B = NonNullable<A>;
이러면 B는 A에서 null과 undefined를 제외하고 가져온다.
-NonNullable 만들기
type A = string | null | undefined | boolean | number;
type B = N<A>;
type N<T> = T extends null | undefined ? never : T;
삼항연산자를 이용해서 null이거나 undefined면 없앤다.
Parameters와 ReturnType
Parameters
function zip(
x: number,
y: string,
z: boolean
): { x: number; y: string; z: boolean } {
return { x, y, z };
}
type Params = Parameters<typeof zip>; // [number, string, boolean]
type a = Params[0]; // number
type b = Params[1]; // string
type c = Params[2]; // boolean
Parameters를 사용하면 배열에 타입을 담아두고 인덱스 번호로 불러올 수 있다.
-Parameters 만들기
function zip(
x: number,
y: string,
z: boolean
): { x: number; y: string; z: boolean } {
return { x, y, z };
}
type P<T extends (...args: any) => any> = T extends (...args: infer A) => any ? A : never;
type Params = P<typeof zip>; // [number, string, boolean]
type a = Params[0]; // number
type b = Params[1]; // string
type c = Params[2]; // boolean
(...args: any) => any는 함수 제한 두는 법이다. 따라서 T는 무조건 함수여야 한다.
infer는 Ts가 알아서 매개변수를 추론한다. 따라서 추론한 값이 있으면 사용하라는 것이고 없으면 사용하지 말라는 의미이다.
ReturnType
function zip(
x: number,
y: string,
z: boolean
): { x: number; y: string; z: boolean } {
return { x, y, z };
}
type Ret = ReturnType<typeof zip>;
ReturnType은 리턴 타입을 가져올 수 있다.
-ReturnType 만들기
function zip(
x: number,
y: string,
z: boolean
): { x: number; y: string; z: boolean } {
return { x, y, z };
}
type R<T extends (...args: any) => any> = T extends (...args: any) => infer A
? A
: never;
type Ret = R<typeof zip>;
infer를 뒤로 빼면 리턴 타입을 가져올 수 있다.
ConstructorParameters와 InstanceType
ConstructorParameters
class A {
a: string;
b: number;
c: boolean;
constructor(a: string, b: number, c: boolean) {
this.a = a;
this.b = b;
this.c = c;
}
}
const c = new A("123", 456, true);
type C = ConstructorParameters<typeof A>;
클래스에서 생성자의 타입을 얻어오고 싶으면 사용하면 된다.
InstanceType
class A {
a: string;
b: number;
c: boolean;
constructor(a: string, b: number, c: boolean) {
this.a = a;
this.b = b;
this.c = c;
}
}
const c = new A("123", 456, true);
type I = InstanceType<typeof A>;
인스턴스의 타입을 얻어오고 싶으면 사용하면 된다.
const a: A = new A("123", 456, true);
클래스는 타입으로 사용할 수 있어서 이렇게 할 수 있다.
'TS > TS(with ZeroCho)' 카테고리의 다른 글
axios 분석 (1) | 2022.09.05 |
---|---|
npm 사이트에서 JS, TS에 따른 설치법 (0) | 2022.08.25 |
TS와 건망증 (0) | 2022.08.20 |
리턴값, 매개변수의 대입 범위 (0) | 2022.08.20 |
타입을 만드는 법 (0) | 2022.08.20 |