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ụ:
1 2 3 4 5 6 7 8 9 10 11 12 13 | <span class="token keyword">interface</span> <span class="token class-name">User</span> <span class="token punctuation">{</span> name<span class="token operator">:</span> string<span class="token punctuation">;</span> age<span class="token operator">:</span> number<span class="token punctuation">;</span> <span class="token punctuation">}</span> type PartialUser <span class="token operator">=</span> Partial<span class="token operator"><</span>User<span class="token operator">></span><span class="token punctuation">;</span> <span class="token comment">// nó sẽ tương tự như sau:</span> type PartialUser <span class="token operator">=</span> <span class="token punctuation">{</span> name<span class="token operator">?</span><span class="token operator">:</span> string <span class="token operator">|</span> <span class="token keyword">undefined</span><span class="token punctuation">;</span> age<span class="token operator">?</span><span class="token operator">:</span> string <span class="token operator">|</span> <span class="token keyword">undefined</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> |
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
1 2 3 4 5 6 7 8 9 10 11 12 13 | <span class="token keyword">interface</span> <span class="token class-name">User</span> <span class="token punctuation">{</span> name<span class="token operator">?</span><span class="token operator">:</span> string <span class="token operator">|</span> <span class="token keyword">undefined</span><span class="token punctuation">;</span> age<span class="token operator">?</span><span class="token operator">:</span> number <span class="token operator">|</span> <span class="token keyword">undefined</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> type RequireUser <span class="token operator">=</span> Required<span class="token operator"><</span>User<span class="token operator">></span><span class="token punctuation">;</span> <span class="token comment">// nó sẽ tương tự như sau:</span> type RequireUser <span class="token operator">=</span> <span class="token punctuation">{</span> name<span class="token operator">:</span> string<span class="token punctuation">;</span> age<span class="token operator">:</span> string<span class="token punctuation">;</span> <span class="token punctuation">}</span> |
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
1 2 3 4 5 6 7 8 9 10 11 12 13 | <span class="token keyword">interface</span> <span class="token class-name">User</span> <span class="token punctuation">{</span> name<span class="token operator">:</span> string<span class="token punctuation">;</span> age<span class="token operator">:</span> number<span class="token punctuation">;</span> <span class="token punctuation">}</span> type ReadonlyUser <span class="token operator">=</span> Readonly<span class="token operator"><</span>User<span class="token operator">></span><span class="token punctuation">;</span> <span class="token comment">// nó sẽ tương tự như sau:</span> type ReadonlyUser <span class="token operator">=</span> <span class="token punctuation">{</span> readonly name<span class="token operator">:</span> string<span class="token punctuation">;</span> readonly age<span class="token operator">:</span> string<span class="token punctuation">;</span> <span class="token punctuation">}</span> |
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | type User <span class="token operator">=</span> <span class="token punctuation">{</span> readonly name<span class="token operator">:</span> string<span class="token punctuation">;</span> readonly age<span class="token operator">:</span> string<span class="token punctuation">;</span> <span class="token punctuation">}</span> type User <span class="token operator">=</span> <span class="token punctuation">{</span> readonly name<span class="token operator">:</span> string<span class="token punctuation">;</span> readonly age<span class="token operator">:</span> number<span class="token punctuation">;</span> <span class="token punctuation">}</span> type Mutable<span class="token operator"><</span><span class="token constant">T</span><span class="token operator">></span> <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token operator">-</span>readonly <span class="token punctuation">[</span><span class="token constant">P</span> <span class="token keyword">in</span> keyof <span class="token constant">T</span><span class="token punctuation">]</span><span class="token operator">:</span> <span class="token constant">T</span><span class="token punctuation">[</span><span class="token constant">P</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> type MutableUser <span class="token operator">=</span> Mutable<span class="token operator"><</span>User<span class="token operator">></span><span class="token punctuation">;</span> <span class="token comment">// lúc này nó sẽ trông như vầy</span> type MutableUser <span class="token operator">=</span> <span class="token punctuation">{</span> name<span class="token operator">:</span> string<span class="token punctuation">;</span> age<span class="token operator">:</span> number<span class="token punctuation">;</span> <span class="token punctuation">}</span> |
- 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
1 2 3 4 | type MakeMutable<span class="token operator"><</span><span class="token constant">T</span><span class="token punctuation">,</span> <span class="token constant">K</span> <span class="token keyword">extends</span> <span class="token class-name">keyof</span> <span class="token constant">T</span><span class="token operator">></span> <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token operator">-</span>readonly <span class="token punctuation">[</span><span class="token constant">P</span> <span class="token keyword">in</span> <span class="token constant">K</span><span class="token punctuation">]</span><span class="token operator">:</span> <span class="token constant">T</span><span class="token punctuation">[</span><span class="token constant">P</span><span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token operator">&</span> Pick<span class="token operator"><</span><span class="token constant">T</span><span class="token punctuation">,</span> Exclude<span class="token operator"><</span>keyof <span class="token constant">T</span><span class="token punctuation">,</span> <span class="token constant">K</span><span class="token operator">>></span> |
- Dưới đây sẽ là ví dụ:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | type User <span class="token operator">=</span> <span class="token punctuation">{</span> readonly name<span class="token operator">:</span> string<span class="token punctuation">;</span> readonly age<span class="token operator">:</span> number<span class="token punctuation">;</span> readonly address<span class="token operator">:</span> string<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">// create a new type that is mutable</span> type MutableUser <span class="token operator">=</span> MakeMutable<span class="token operator"><</span>User<span class="token punctuation">,</span> <span class="token string">'name'</span><span class="token operator">></span> <span class="token keyword">const</span> user<span class="token operator">:</span> MutableUser <span class="token operator">=</span> <span class="token punctuation">{</span> name<span class="token operator">:</span> <span class="token string">'John'</span><span class="token punctuation">,</span> age<span class="token operator">:</span> <span class="token number">30</span><span class="token punctuation">,</span> address<span class="token operator">:</span> <span class="token string">'123 Main St.'</span><span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token comment">// Cannot assign to 'age' because it is a read-only property</span> user<span class="token punctuation">.</span>age <span class="token operator">=</span> <span class="token number">10</span> |
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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <span class="token keyword">interface</span> <span class="token class-name">User</span> <span class="token punctuation">{</span> name<span class="token operator">:</span> string<span class="token punctuation">;</span> age<span class="token operator">:</span> number<span class="token punctuation">;</span> address<span class="token operator">:</span> string<span class="token punctuation">;</span> <span class="token punctuation">}</span> type UserWithoutNameAndAge <span class="token operator">=</span> Omit<span class="token operator"><</span>User<span class="token punctuation">,</span> <span class="token string">'name'</span> <span class="token operator">|</span> <span class="token string">'age'</span> <span class="token operator">></span> <span class="token comment">// nó sẽ tương tự như sau</span> type UserWithoutNameAndAge <span class="token operator">=</span> <span class="token punctuation">{</span> address<span class="token operator">:</span> string<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">// 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</span> |
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
1 2 3 4 5 6 7 8 9 10 11 12 13 | <span class="token keyword">interface</span> <span class="token class-name">User</span> <span class="token punctuation">{</span> name<span class="token operator">:</span> string<span class="token punctuation">;</span> age<span class="token operator">:</span> number<span class="token punctuation">;</span> address<span class="token operator">:</span> string<span class="token punctuation">;</span> <span class="token punctuation">}</span> type UserWithNameAndAge <span class="token operator">=</span> Pick<span class="token operator"><</span>User<span class="token punctuation">,</span> <span class="token string">'name'</span> <span class="token operator">|</span> <span class="token string">'age'</span><span class="token operator">></span> <span class="token comment">// nó sẽ tương tự như sau</span> type UserWithNameAndAge <span class="token operator">=</span> <span class="token punctuation">{</span> name<span class="token operator">:</span> string<span class="token punctuation">;</span> age<span class="token operator">:</span> string<span class="token punctuation">;</span> <span class="token punctuation">}</span> |
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
1 2 3 4 5 6 | type TestNumberOrString <span class="token operator">=</span> number <span class="token operator">|</span> string type RemoveString <span class="token operator">=</span> Exclude<span class="token operator"><</span>TestNumberOrString<span class="token punctuation">,</span> string<span class="token operator">></span> <span class="token comment">// nó sẽ tương tự như sau:</span> type RemoveString <span class="token operator">=</span> number<span class="token punctuation">;</span> |
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
1 2 3 4 5 6 | type TestNumberOrString <span class="token operator">=</span> number <span class="token operator">|</span> string type PickString <span class="token operator">=</span> Extract<span class="token operator"><</span>TestNumberOrString<span class="token punctuation">,</span> string<span class="token operator">></span> <span class="token comment">// nó sẽ tương tự như sau:</span> type PickString <span class="token operator">=</span> string<span class="token punctuation">;</span> |
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
1 2 3 4 5 6 7 8 | <span class="token keyword">const</span> functionA <span class="token operator">=</span> <span class="token punctuation">(</span>a<span class="token operator">:</span> number<span class="token punctuation">,</span> b<span class="token operator">:</span> number<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token parameter">number</span> <span class="token operator">=></span> a <span class="token operator">+</span> b<span class="token punctuation">;</span> type ParameterFuncA <span class="token operator">=</span> Parameters<span class="token operator"><</span><span class="token keyword">typeof</span> functionA<span class="token operator">></span><span class="token punctuation">;</span> <span class="token comment">// nó sẽ có dạng như sau</span> type ParameterFuncA <span class="token operator">=</span> <span class="token punctuation">[</span>a<span class="token operator">:</span> number<span class="token punctuation">,</span> b<span class="token operator">:</span> number<span class="token punctuation">]</span> <span class="token comment">// cách sử dụng</span> <span class="token keyword">const</span> newArgs<span class="token operator">:</span> ParameterFuncA <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">;</span> |
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ó
1 2 3 4 5 6 7 8 | <span class="token keyword">const</span> functionA <span class="token operator">=</span> <span class="token punctuation">(</span>a<span class="token operator">:</span> number<span class="token punctuation">,</span> b<span class="token operator">:</span> number<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token parameter">number</span> <span class="token operator">=></span> a <span class="token operator">+</span> b<span class="token punctuation">;</span> type ReturnTypeFuncA <span class="token operator">=</span> ReturnType<span class="token operator"><</span><span class="token keyword">typeof</span> functionA<span class="token operator">></span><span class="token punctuation">;</span> <span class="token comment">// nó sẽ tương tự như sau</span> type ReturnTypeFuncA <span class="token operator">=</span> number<span class="token punctuation">;</span> <span class="token comment">// cách sử dụng</span> <span class="token keyword">const</span> returnType<span class="token operator">:</span> ReturnTypeFuncA <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span> |
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
1 2 3 4 5 | type promiseNumber <span class="token operator">=</span> Promise<span class="token operator"><</span>number<span class="token operator">></span> type justNumber <span class="token operator">=</span> Awaited<span class="token operator"><</span>promiseNumber<span class="token operator">></span> <span class="token comment">// type justNumber = number</span> |
chúng ta có thể kết hợp với ReturnType để thực hiện như sau:
1 2 3 4 5 6 7 | <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">fetchData</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">:</span> Promise<span class="token operator"><</span>string<span class="token operator">></span> <span class="token punctuation">{</span> <span class="token comment">// fetch data and return a string</span> <span class="token punctuation">}</span> type ResolvedResult <span class="token operator">=</span> Awaited<span class="token operator"><</span>ReturnType<span class="token operator"><</span><span class="token keyword">typeof</span> fetchData<span class="token operator">>></span><span class="token punctuation">;</span> <span class="token comment">// type ResolvedResult = string</span> |
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
1 2 3 4 5 6 | type name <span class="token operator">=</span> string <span class="token operator">|</span> <span class="token keyword">undefined</span> <span class="token operator">|</span> <span class="token keyword">null</span><span class="token punctuation">;</span> type nameRequired <span class="token operator">=</span> NonNullable<span class="token operator"><</span>name<span class="token operator">></span><span class="token punctuation">;</span> <span class="token comment">// lúc này nó sẽ tương tự như sau</span> type nameRequired <span class="token operator">=</span> string<span class="token punctuation">;</span> |
- Đố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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | type MakeNullable<span class="token operator"><</span><span class="token constant">T</span><span class="token punctuation">,</span> <span class="token constant">K</span> <span class="token keyword">extends</span> <span class="token class-name">keyof</span> <span class="token constant">T</span><span class="token operator">></span> <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token punctuation">[</span><span class="token constant">P</span> <span class="token keyword">in</span> keyof <span class="token constant">T</span><span class="token punctuation">]</span><span class="token operator">:</span> <span class="token constant">P</span> <span class="token keyword">extends</span> <span class="token class-name">K</span> <span class="token operator">?</span> NonNullable<span class="token operator"><</span><span class="token constant">T</span><span class="token punctuation">[</span><span class="token constant">P</span><span class="token punctuation">]</span><span class="token operator">></span> <span class="token operator">:</span> <span class="token constant">T</span><span class="token punctuation">[</span><span class="token constant">P</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token comment">// Cách sử dụng</span> type User <span class="token operator">=</span> <span class="token punctuation">{</span> name<span class="token operator">:</span> string<span class="token punctuation">;</span> age<span class="token operator">:</span> number <span class="token operator">|</span> <span class="token keyword">undefined</span><span class="token punctuation">;</span> address<span class="token operator">:</span> string <span class="token operator">|</span> <span class="token keyword">null</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token comment">// Chuyển đổi name và age thành non-nullable</span> type NonNullableUser <span class="token operator">=</span> MakeNullable<span class="token operator"><</span>User<span class="token punctuation">,</span> <span class="token string">'name'</span> <span class="token operator">|</span> <span class="token string">'age'</span><span class="token operator">></span><span class="token punctuation">;</span> <span class="token keyword">const</span> user<span class="token operator">:</span> NonNullableUser <span class="token operator">=</span> <span class="token punctuation">{</span> name<span class="token operator">:</span> <span class="token string">'John'</span><span class="token punctuation">,</span> age<span class="token operator">:</span> <span class="token number">30</span><span class="token punctuation">,</span> address<span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword">const</span> user2<span class="token operator">:</span> NonNullableUser <span class="token operator">=</span> <span class="token punctuation">{</span> name<span class="token operator">:</span> <span class="token string">'Mary'</span><span class="token punctuation">,</span> age<span class="token operator">:</span> <span class="token number">25</span><span class="token punctuation">,</span> address<span class="token operator">:</span> <span class="token string">'123 Main St.'</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token comment">// Compiler error: Property 'age' is missing</span> <span class="token keyword">const</span> user3<span class="token operator">:</span> NonNullableUser <span class="token operator">=</span> <span class="token punctuation">{</span> name<span class="token operator">:</span> <span class="token string">'David'</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> |
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.