TypeScript 中的条件类型详解
在 TypeScript 中,条件类型是一种高级类型,它的能力可以帮助我们更好地控制变量的类型。条件类型可以根据某个类型表达式的真假来确定最终的类型。通过条件判断,可以实现复杂类型的推断和转换。
例如,我们有一个函数 pick
,它接受一个对象和一组属性名称,返回一个新对象,该对象包含原对象中指定属性的键值对。我们可能会这样实现它:
-- -------------------- ---- ------- -------- --------- ------- ----- ---------- ------ - ----- ------ - --- --- ------ --- -- ----- - -- ------------------------- - ----------- - --------- - - ------ ------- -
我们可以调用 pick
函数来选择一个对象的子集,并指定它们的属性名称:
const user = { name: 'Alice', age: 30, email: 'alice@example.com' }; const picked = pick(user, ['name', 'age']); console.log(picked); // { name: 'Alice', age: 30 }
尽管这个函数很简单,但却有一个问题。假设我们的对象拥有可选属性,那么在调用 obj[key]
时,TypeScript 编译器会报告错误,因为这个表达式可能会返回 undefined:
interface User { name: string; age: number; email?: string; } const user: User = { name: 'Alice', age: 30 }; const picked = pick(user, ['name', 'age', 'email']); // Error: Property 'email' does not exist on type 'User'.
我们现在需要定义一个条件类型,它应该接受一个对象类型和一个属性名称集合类型,如果属性名称集合中的某个属性可以从对象类型中获取,则返回该属性的类型,否则返回未定义类型 undefined
:
type Pick<T, K extends keyof T> = ...;
这个类型的实现可能看起来非常复杂,但我们可以一步一步构建它。首先,我们定义一个类型变量 Prop
,它用来表示条件类型的属性:
type Pick<T, K extends keyof T> = K extends Prop ? T[Prop] : undefined;
现在我们需要定义一个属性名称类型的联合类型,这个联合类型应该包含属性名称集合中的所有属性名称。我们可以使用 UnionToIntersection
辅助类型将联合类型转换为交叉类型:
-- -------------------- ---- ------- ---- ------- - - ------- --- - --- -- -- ---- - ------ ---- -------- - ----------------------------------------- ----- ---- ------- - ------- ----- -- - - ------- ----- -------- - ---- - ---------- --------- ---- - ----- ------- ---- ------- ------- ------- - ---- ------ - ---------- ------ - ------- -- - ----- ------- ---- ------- - ---- --------- - ---------- ------- - --------- -- ---------
现在我们的条件类型可以正确处理可选属性。如果我们尝试从对象类型中选择一个不存在的属性,编译器将不再报告错误,而是根据条件类型的实现返回 undefined
。
总结
在 TypeScript 中,条件类型是非常强大的高级类型。通过判断类型表达式的真假,可以实现复杂类型的推断和转换。在编写类型安全的函数和组件时,条件类型可以起到非常重要的作用。
示例代码
-- -------------------- ---- ------- --------- ---- - ----- ------- ---- ------- ------- ------- ------- ------- - ---- ------- - - ------- --- - --- -- -- ---- - ------ ---- -------- - ----------------------------------------- ----- ---- ------- - ------- ----- -- - - ------- ----- -------- - ---- - ---------- ---- ------ - ---------- ------ - ------- -- - ----- ------- ---- ------- - ---- --------- - ---------- ------- - --------- -- --------- -------- ------- - ------- ----- -------------- -- ----- ----- ------- -- - ----- ------ - -- -- ------- --- --- ------ --- -- ----- - -- ------------------------- - ----------- - --------- - - ------ ------- - ----- ----- ---- - - ----- -------- ---- -- -- ----- ------ - ---------- -------- ------ ---------- -------------------- -- - ----- -------- ---- -- -
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/6451ea98675af4061b5a4cc3