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은 프로퍼티를 모두 옵셔널로 바꿔준다.
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";
// }
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(읽기전용)로 바꿔준다.
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! 재할당 불가
아래 예시는 학년과 성적을 표시하는 인터페이스 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",
}
전달 받은 파라미터 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;
}
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",
}
T
타입에서 K
프로퍼티를 생략하고 사용할 수 있다.
interface User {
id: number;
name: string;
age: number;
gender: "M" | "W";
}
const admin: Omit<User, "age" | "gender"> = {
id: 0,
name: "Harry",
}
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
는 타입을 제거한다.
null
과 undefined
을 제외한 타입을 생성한다.
type T1 = string | null | undefined | void;
type T2 = NonNullable<T1>;
T2의 타입은 T1의 타입 중 null
과 undefined
가 제외된 string | void
가 된다.