Utility Types in TypeScript
TypeScript 提供了一些內建的 Utility Types,可以幫助我們更方便地操作型別。
Utility Types
Pick
Pick Utility Type 可以從一個 Interface 中選擇一些屬性,形成一個新的 Interface。
當你只需要某個 Interface 的部分屬性時,可以使用 Pick Utility Type。
interface Todo {
title: string;
description: string;
completed: boolean;
}
// 只選擇 description 和 completed 屬性
type TodoPreview = Pick<Todo, "description" | "completed">;
function updateTodo(todo: Todo, fieldsToUpdate: TodoPreview) {
return {
...todo,
...fieldsToUpdate,
};
}
const todo1 = updateTodo(
{
title: "Old Title",
description: "Old Description",
completed: false,
},
// 只需要傳入 description 和 completed 屬性
{
description: "New Description",
completed: true,
},
);
console.log(todo1);
Omit
Omit Utility Type 與 Pick Utility Type 相反,可以從一個 Interface 中排除一些屬性,形成一個新的 Interface。
當你只需要某個 Interface 的部分屬性時,可以使用 Omit Utility Type。
interface Todo {
title: string;
description: string;
completed: boolean;
}
// 排除 description 和 completed 屬性
type TodoPreview = Omit<Todo, "description" | "completed">;
function updateTodo(todo: Todo, fieldsToUpdate: TodoPreview) {
return {
...todo,
...fieldsToUpdate,
};
}
const todo1 = updateTodo(
{
title: "Old Title",
description: "Old Description",
completed: false,
},
// 只需要傳入 title 屬性
{
title: "New Title",
},
);
console.log(todo1);
Partial
Partial Utility Type 可以將一個 Interface 的所有屬性都轉換為可選的 (optional)。
當你只需要某個 Interface 的部分屬性時,可以使用 Partial Utility Type。
interface Todo {
title: string;
description: string;
completed: boolean;
}
// 將所有屬性都轉換為可選的
function updateTodo(todo: Todo, fieldsToUpdate: Partial<Todo>) {
return {
...todo,
...fieldsToUpdate,
};
}
const todo1 = updateTodo(
{
title: "Old Title",
description: "Old Description",
completed: false,
},
// 只需要傳入 title 和 description 屬性
{
title: "New Title",
description: "New Description",
},
);
console.log(todo1);
Required
Required Utility Type 可以將一個 Interface 的所有屬性都轉換為必填的 (required)。
Interface 有些屬性可能為可選的 (optional),使用 Required Utility Type 可以將這些可選的屬性轉換為必填的。
interface Todo {
title: string;
// description 是可選的
description?: string;
completed: boolean;
}
// 將所有屬性都轉換為必填的
function updateTodo(todo: Todo, fieldsToUpdate: Required<Todo>) {
return {
...todo,
...fieldsToUpdate,
};
}
const todo1 = updateTodo(
{
title: "Old Title",
description: "Old Description",
completed: false,
},
// 只需要傳入 title 和 description 屬性
{
title: "New Title",
// description 變成必填的
description: "New Description",
completed: true,
},
);
console.log(todo1);
Readonly
Readonly Utility Type 可以將一個 Interface 的所有屬性都轉換為只讀的 (readonly)。
當你只需要某個 Interface 的部分屬性時,可以使用 Readonly Utility Type。
interface Todo {
title: string;
description: string;
completed: boolean;
}
type T = Readonly<Todo>;
const todo1: T = {
title: "Old Title",
description: "Old Description",
completed: false,
};
// 下面這行會出現錯誤,因為 title 是只讀的
// Cannot assign to 'title' because it is a read-only property.(2540)
todo1.title = "New Title";
Record
Record Utility Type
type User = {
id: string
name: string
age: number
}
// 建立一個 key-value pair 的 type,key 是 string,value 是 User
type T = Record<string, User>
const a: T = {
"1_allen": {
id: "1",
name: "Allen",
age: 25,
},
"2_bob": {
id: "2",
name: "Bob",
age: 30,
},
}
// 建立一個 key-value pair 的 type,key 是 "admin" 或 "user",value 是 User
type U = Record<"admin" | "user", User>
const b: U = {
"admin": {
id: "1",
name: "Allen",
age: 25,
},
"user": {
id: "2",
name: "Bob",
age: 30,
},
}
Extract
可以從 Type 中提取出符合條件的 Type。
type Role = "admin" | "user" | "guest"
type Permission = "read" | "write" | "delete"
type OtherRole = "testing" | "admin" | "user" | "guest" | "moderator"
type AdminRole = Extract<Role, "admin">
type UserPermission = Extract<Permission, "read" | "write">
// 類似交集,只提取 Role 在 OtherRole 中的共通部分
type T = Extract<Role, OtherRole>
Exclude
可以從 Type 中排除出不符合條件的 Type。
type Role = "admin" | "user" | "guest"
type Permission = "read" | "write" | "delete"
type OtherRole = "testing" | "admin" | "user" | "guest" | "moderator"
type AdminRole = Exclude<Role, "admin">
type UserPermission = Exclude<Permission, "read" | "write">
// 類似差集,排除 Role 在 OtherRole 中的共通部分
type T = Exclude<Role, OtherRole>
ReturnType
ReturnType Utility Type 可以從一個 Function Type 中提取出返回值的 Type。
function getUser() {
return { id: 1, name: "Allen", age: 25 }
}
type T = ReturnType<typeof getUser>
const user: T = {
id: 1,
name: "Allen",
age: 25,
}
Parameters
Parameters Utility Type 可以從一個 Function Type 中提取出參數的 Type。
當你有一個函式的參數想參照其他函式的參數時,可以使用 Parameters Utility Type。
function getUser(id: number) {
return { id , name: "Allen", age: 25 }
}
type T = Parameters<typeof getUser>
const id: T = [1]
ConstructorParameters
ConstructorParameters Utility Type 可以從一個 Class 中提取出建構子的參數的 Type。
class User {
constructor(public id: number, public name: string, public age: number) {}
}
type T = ConstructorParameters<typeof User>
const user: T = [1, "Allen", 25]
InstanceType
有點莫名其妙的 Utility Type
InstanceType Utility Type 可以從一個 Class 中提取出建構子的返回值的 Type。
class User {
constructor(public id: number, public name: string, public age: number) {}
}
type T = InstanceType<typeof User>
// 上面這一句等同於下面這一句,所以 InstanceType 是用途有點微妙的 Utility Type
type T = User
NonNullable
NonNullable Utility Type 可以從一個 Type 中排除出 null 和 undefined 的 Type。
type A = string | number | null | undefined
// T 會排除掉 null 和 undefined,只剩下 string | number
type T = NonNullable<A>
Awaited
Awaited Utility Type 可以從一個 Promise Type 中提取出返回值的 Type。
function getUser() {
return Promise.resolve({ id: 1, name: "Allen", age: 25 })
}
// T 會提取出 Promise 的返回值的 Type
// type T = { id: number; name: string; age: number }
type T = Awaited<ReturnType<typeof getUser>>
字串相關的 Utility Type
type T = Uppercase<"hello"> // "HELLO"
type T = Lowercase<"HELLO"> // "hello"
type T = Capitalize<"hello"> // "Hello"
type T = Uncapitalize<"Hello"> // "hello"
