建立於 2025-12-11 更新於 2026-09-02
# typescript

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"

參考資料

  • You are a Junior Dev if You Don’t Know These 18 TypeScript Utility Types