+15

Typescript utility types phổ biến

Mọi người khi làm việc với JS chắc cũng không còn quá xa lạ với TS. Vì lẻ đó, hôm nay mình sẽ giới thiệu một số Utility types phổ biến trong TS. Đây hầu hết là những Global types sẵn có của TS. Không cần setup gì thêm, bắt đầu nào.

Partial

Đây là một utility type cho phép bạn tạo nhanh một type với các thuộc tính optional hoặc undefined từ một type sẵn có. Dưới đây là ví dụ:

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

type PartialUser = Partial<User>;

// nó sẽ tương tự như sau:
type PartialUser = {
    name?: string | undefined;
    age?: string | undefined;
}

Required

Ngược lại với Partial thì đây là một utility cho phép tạo type mới với thuộc tính required

interface User {
  name?: string | undefined;
  age?: number | undefined;
}

type RequireUser = Required<User>;

// nó sẽ tương tự như sau:
type RequireUser =  {
    name: string;
    age: string;
}

Readonly

Với utility này chúng ta sẽ dễ dàng tạo type mới với các thuộc tính readonly từ một type đã được định nghĩa trước đó, khi đó các thuộc tính này sẽ không thể sửa đổi sau khi được khởi tạo

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

type ReadonlyUser = Readonly<User>;

// nó sẽ tương tự như sau:
type ReadonlyUser = {
    readonly name: string;
    readonly age: string;
}

Mutable

Đây không phải là utility được cung cấp bới TS, nhưng trong quá trình làm việc thì sinh ra utility này. Nó giúp chúng ta convert các thuộc tính readonly của một type nào đó trở lại thành mutable

  1. Nếu bạn muốn thay đổi tất cả các thuộc tính trong type User thành mutable thì cách viết như sau:
type User = {
    readonly name: string;
    readonly age: string;
}

type User = {
  readonly name: string;
  readonly age: number;
}

type Mutable<T> = {
  -readonly [P in keyof T]: T[P];
}

type MutableUser = Mutable<User>;
// lúc này nó sẽ trông như vầy
type MutableUser = {
    name: string;
    age: number;
}
  1. Nếu bạn chỉ muốn chuyển một thuộc tính của type thành mutalble thì sẽ như vầy:
  • Tạo một generic type gọi là MakeMutable, type này sẽ nhận vào 2 tham số
    • Tham số T: Đây là đại diện cho kiểu dữ liệu mà bạn muốn thay đổi
    • Tham số K extends keyof T: Đây là đại diện cho các union type chứa các thuộc tính mà bạn muốn chuyển đối nó thành mutable
  • Trong body của MakeMutable thực hiện loop qua các union type và remove readonly của các thuộc tính đó, đồng thời sẽ giữ lại các thuộc tính không cần chuyển đổi mutable thông qua sử dụng uitility Pick
type MakeMutable<T, K extends keyof T> = {
  -readonly [P in K]: T[P]
} & Pick<T, Exclude<keyof T, K>>
  • Dưới đây sẽ là ví dụ:
type User = {
  readonly name: string;
  readonly age: number;
  readonly address: string;
}

// create a new type that is mutable
type MutableUser = MakeMutable<User, 'name'>

const user: MutableUser = {
  name: 'John',
  age: 30,
  address: '123 Main St.',
}
// Cannot assign to 'age' because it is a read-only property
user.age = 10

Omit

Trong lodash có omit, và trong TS cũng vậy, utility này nó sẽ làm bạn nhớ đến omit của lodash, đó là bỏ ra những thuộc tính không cần dùng trong một đối tượng nào đó. Xem ví dụ các bạn sẽ dễ hiểu hơn

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

type UserWithoutNameAndAge = Omit<User, 'name' | 'age' >

// nó sẽ tương tự như sau
type UserWithoutNameAndAge = {
    address: string;
}
// lúc này 2 thuộc tính name và age đã không còn trong type OmitUser của chúng ta nữa

Pick

Pick cho phép chúng ta chọn ra những thuộc tính nào cần sử dụng của một đối tượng cụ thể nó sẽ ngược lại với Omit ở trên

interface User {
  name: string;
  age: number;
  address: string;
}
type UserWithNameAndAge = Pick<User, 'name' | 'age'>

// nó sẽ tương tự như sau
type UserWithNameAndAge = {
 name: string;
 age: string;
}

Exclude

Utility này cho phép bạn loại bỏ một hay nhiều type từ union type của một thuộc tính khi tạo mới từ type có sẵn

type TestNumberOrString = number | string

type RemoveString = Exclude<TestNumberOrString, string>
// nó sẽ tương tự như sau:
type RemoveString = number;

Extract

Ngược lại với Exclude, Extract cho phép bạn chọn một hay nhiều type từ union type của một thuộc tính

type TestNumberOrString = number | string

type PickString = Extract<TestNumberOrString, string>
// nó sẽ tương tự như sau:
type PickString = string;

Parameters

Cho phép bạn dễ dàng extract type của các paramaters từ một function bất kỳ, xem ví dụ bên dưới nhe

const functionA = (a: number, b: number): number => a + b;

type ParameterFuncA = Parameters<typeof functionA>;
// nó sẽ có dạng như sau
type ParameterFuncA = [a: number, b: number]
// cách sử dụng
const newArgs: ParameterFuncA = [1, 2];

ReturnType

Cho phép bạn tạo mới một type từ return type của một function được sẵn có

const functionA = (a: number, b: number): number => a + b;

type ReturnTypeFuncA = ReturnType<typeof functionA>;
// nó sẽ tương tự như sau
type ReturnTypeFuncA = number;
// cách sử dụng
const returnType: ReturnTypeFuncA = 1;

Awaited

Na ná với ReturnType, nhưng khác một chút là utility này cho phép bạn extract return type từ resolve type của promise hay await function

type promiseNumber = Promise<number>

type justNumber = Awaited<promiseNumber>
// type justNumber = number

chúng ta có thể kết hợp với ReturnType để thực hiện như sau:

async function fetchData(): Promise<string> {
  // fetch data and return a string
}

type ResolvedResult = Awaited<ReturnType<typeof fetchData>>;
// type ResolvedResult = string

NonNullable

  1. Nếu bạn đang có type được định nghĩa bằng union type trong đó có undefined or null, và bạn muốn tạo type mới từ type sẵn có đó nhưng muốn loại bỏ undefined hoặc null, thì uitility này sẽ giúp bạn làm việc đó nhanh chóng
type name = string | undefined | null;

type nameRequired = NonNullable<name>;
// lúc này nó sẽ tương tự như sau
type nameRequired = string;
  1. Đối với một đối tượng có nhiều thuộc tính thì sẽ làm như sau:
  • Tạo một generic type MakeNullable, type này sẽ nhận vào 2 tham số
    • Tham số T: Đây là đại diện cho kiểu dữ liệu mà bạn muốn thay đổi
    • Tham số K extends keyof T: Đây là đại diện cho các union type chứa các thuộc tính mà bạn muốn chuyển đối nó thành non-nullable
  • Trong body của MakeNullable chúng ta sẽ thực hiện lặp lại các thuộc tính T và kiểm tra xem nó có nằm trong danh sách union của K hay không, nếu có thì chúng ta sẽ thực hiện NonNullable cho thuộc tính đó, ngược lại thì giữ nguyên
type MakeNullable<T, K extends keyof T> = {
  [P in keyof T]: P extends K ? NonNullable<T[P]> : T[P]
};

// Cách sử dụng
type User = {
  name: string;
  age: number | undefined;
  address: string | null;
};

// Chuyển đổi name và age thành non-nullable
type NonNullableUser = MakeNullable<User, 'name' | 'age'>;

const user: NonNullableUser = {
  name: 'John',
  age: 30,
  address: null,
};

const user2: NonNullableUser = {
  name: 'Mary',
  age: 25,
  address: '123 Main St.',
};

// Compiler error: Property 'age' is missing
const user3: NonNullableUser = {
  name: 'David',
};

Trên đây mình đã giới thiệu một số utility mình thấy hay thường sử dụng khi làm việc với TS, bằng việc nắm cơ bản các utilities trên các bạn sẽ có thể kết hợp để define các generic type nâng cao hơn phù hợp với nhu cầu công việc. Mong nhận được sự góp ý từ mọi người. Xin chân thành cảm ơn


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí