[TypeScript] 유틸리티 타입

해리포터·2023년 1월 17일
0
post-thumbnail

keyof 키워드

keyof 키워드를 사용하면 인터페이스의 key 값들을 유니언의 형태로 받을 수 있다.

interface User {
	id: number;
	name: string;
	age: number;
	gender: "m" | "f";
}

type UserKey = keyof User; // 'id' | 'name' | 'age' | 'gender' 과 같다

const uk: UserKey = "job"; // ❌ error! id, name, age, gender 이외의 값을 할당하면 에러가 발생한다.

Partial<타입>

Partial은 프로퍼티를 모두 옵셔널로 바꿔준다.

interface User {
	id: number;
	name: string;
	age: number;
	gender: "m" | "f";
}

let admin: User = { // ❌ error! age와 gender가 없어서 에러가 발생
	id: 1,
	name: "Harry",
}

Partial<T>을 사용해서 에러를 해결할 수 있다.

interface User {
	id: number;
	name: string;
	age: number;
	gender: "m" | "f";
}

let admin: Partial<User> = { // ⭕️
	id: 1,
	name: "Harry",
}

// partial을 사용하면 아래와 동일하게 작용한다.
// interface User {
// 	id?: number;
// 	name?: string;
//	age?: number;
// 	gender?: "m" | "f";
// }

Required<타입>

Partial과 반대로, 모든 프로퍼티를 필수로 바꿔준다.

interface User {
	id: number;
	name: string;
	age?: number;
}

let admin: User = { // age는 옵셔널 프로퍼티이기 때문에 age가 없어도 에러가 발생하지 않는다.
	id: 1,
	name: "Harry",
}

Requried<T>를 사용하면, 인터페이스에 있는 모든 프로퍼티가 필수 프로퍼티로 바뀌기 때문에 모든 프로퍼티를 명시해야 한다. 그렇지 않으면 타입스크립트는 에러를 발생시킨다.

interface User {
	id: number;
	name: string;
	age?: number;
}

let admin: Required<User> = { // ❌ age가 없기 때문에 에러가 발생한다.
	id: 1,
	name: "Harry",
}

에러를 해결하기 위해서는 해당 인터페이스의 모든 프로퍼티를 명시해야 한다.

interface User {
	id: number;
	name: string;
	age?: number;
}

let admin: Required<User> = { 
	id: 1,
	name: "Harry",
	age: 30, // age도 필수
}

Readonly<타입>

모든 프로퍼티를 readonly(읽기전용)로 바꿔준다.

interface User {
	id: number;
	name: string;
	age?: number;
}

let admin: User = {
	id: 1,
	name: "Harry",
};

admin.id = 4; // ⭕️ 이후 재할당 가능

Readonly<T>를 사용하면 모든 프로퍼티가 읽기 전용이 되기 때문에 선언 이후 수정이 불가하다.

interface User {
	id: number;
	name: string;
	age?: number;
}

let admin: Readonly<User> = {
	id: 1,
	name: "Harry",
};

admin.id = 4; // ❌ error! 재할당 불가

Record<키, 타입>

예시 1

아래 예시는 학년과 성적을 표시하는 인터페이스 Score이다.

interface Score {
	"1": "A" | "B" | "C" | "D";
	"2": "A" | "B" | "C" | "D";
	"3": "A" | "B" | "C" | "D";
	"4": "A" | "B" | "C" | "D";
}

const score: Score = {
	1: "A",
	2: "C",
	3: "B", 
	4: "D",
}

위의 예시를 Record<K, T>를 활용하면 아래와 같다.

const socre: Record<"1" | "2" | "3" | "4", "A" | "B" | "C" | "D"> = {
	1: "A",
	2: "C",
	3: "B",
	4: "D",
};

가독성을 높이기 위해서 학년과 성적을 타입으로 분리해서 작성하면 아래와 같다.

type Grade = "1" | "2" | "3" | "4";
type Score = "A" | "B" | "C" | "D";

const score: Record<Grade, Score> = {
	1: "A",
	2: "C",
	3: "B",
	4: "D",
}

예시2

전달 받은 파라미터 user의 값이 유효한지 확인하는 함수 isValid가 있다.

interface User {
	id: number;
	name: string;
	age: number;
}

function isValid(user: User) {
	const result = {
		id: user.id > 0,
		name: user.name !== '',
		age: user.age > 0,
	}
	return result;
}

Record<K, T>keyof 키워드를 활용해서 함수 isValid 내부의 result 객체의 타입을 아래와 같이 나타낼 수 있다.

(💡 user.id > 0, user.name !== '', user.age > 0 는 boolean 이다)

interface User {
	id: number;
	name: string;
	age: number;
}

function isValid(user: User) {
	const result: Record<keyof User, boolean> = {
		id: user.id > 0,
		name: user.name !== '',
		age: user.age > 0,
	}
	return result;
}

Pick<T, K>

T 타입에서 K 프로퍼티만 고를 수 있다.

interface User {
	id: number;
	name: string;
	age: number;
	gender: "M" | "W";
}

const admin = { // ❌ error! age와 gender
	id: 0,
	name: "Harry",
}
interface User {
	id: number;
	name: string;
	age: number;
	gender: "M" | "W";
}

const admin: Pick<User, "id" | "name"> = {
	id: 0,
	name: "Harry",
}

Omit<T, K>

T 타입에서 K 프로퍼티를 생략하고 사용할 수 있다.

interface User {
	id: number;
	name: string;
	age: number;
	gender: "M" | "W";
}

const admin: Omit<User, "age" | "gender"> = {
	id: 0,
	name: "Harry",
}

Exclude<T1, T2>

T1 타입에서 T2 타입을 제외하고 사용할 수 있다. (T1 타입 중에서 T2 타입과 겹치는 타입을 제외시킨다.)

type T1 = string | number;
type T2 = Exclude<T1, number>;

T2에 마우스를 hover하면, T2의 타입은 string만 남는 것을 확인할 수 있다.

type T1 = string | number | boolean;
type T2 = Exclude<T1, number | string>;

위의 예시에서 Exclude에서 유니언 타입을 사용하면 T2의 타입은 boolean이 된다.

💡 Omit 과 Exclude의 차이점?

Omit프로퍼티를 제거하는 것이고, Exclude타입을 제거한다.


NonNullable<타입>

nullundefined 을 제외한 타입을 생성한다.

type T1 = string | null | undefined | void;
type T2 = NonNullable<T1>;

T2의 타입은 T1의 타입 중 nullundefined가 제외된 string | void가 된다.


References

TypeScript #8 유틸리티 타입 Utility Types

profile
FE Developer 매일 한 걸음씩!

0개의 댓글