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
- 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;
}
- 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
- 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;
- Đố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