TypeScript 類型挑戰:實現 Pick
高質量的類型可以提高項目的可維護性并避免一些潛在的漏洞。
一些大廠在前端面試中也考察到了 TypeScript 高級類型的定義,本系列主要解答來自 Type Challenges 中的 TS 類型挑戰問題,以此更好的了解 TS 的類型系統,編寫自己的類型工具。
下面來看一個難度為簡單的題目:實現 Pick
題目描述
實現 TS 內置的 Pick,但不可以使用它。
從類型 T 中選擇出屬性 K,構造成一個新的類型。
例如:
interface Todo {
title: string
description: string
completed: boolean
}
type TodoPreview = MyPick<Todo, 'title' | 'completed'>
const todo: TodoPreview = {
title: 'Clean room',
completed: false,
}
題目解答
Pick 類型用于從T類型中選擇部分屬性K來構造新的類型。
首先,我們需要遍歷對象 T。那就要使用映射類型來遍歷:
type MappedType<T> = {
[Key in keyof T]: T[Key];
};
- keyof T用于從對象類型T中獲取鍵值 key;
- in用于對對象鍵值key進行迭代;
- Key 就是對象鍵值 key 本身;
- T[Key]是指定 Key 的值;
然后,要想迭代獲取對象的某個部分,就需要指定要迭代的key:
type MappedType<T, Keys> = {
[Key in Keys]: T[Key];
};
但是,這樣寫就會有兩個錯誤:
- 不能將類型“Keys”分配給類型“string | number | symbol”。
- 類型“Key”無法用于索引類型“T”。
這兩個錯誤都與迭代規則有關:
- key 可以是string、number、symbol;
- 如果T中不存在Key,就不能調用T[Key]。
如果規則 2 成立,那么規則 1 一定是成立的,因為現有的 keys 是指定類型之一。為了迭代現有的 key,我們需要使用extends關鍵字進行約束。這樣,如果指定不存在的 key,TypeScript 將拋出一個錯誤,如果T中不存在這個 key,就不能調用T[key]。
Pick的實現如下:
type MyPick<T, Keys extends keyof T> = {
[Key in Keys]: T[Key];
};
Type Challenges:https://github.com/type-challenges/type-challenges