MST

星途 面试题库

面试题:TypeScript类型兼容性与复杂泛型的结合

定义两个泛型类型 `type Fn1<T extends { a: number }> = (arg: T) => T['a'];` 和 `type Fn2<T extends { a: number, b: string }> = (arg: T) => T['a'];`。请分析在不同编译选项下,`Fn1`类型的函数能否赋值给`Fn2`类型的函数,详细说明推理过程和涉及到的类型兼容性规则。
35.4万 热度难度
前端开发TypeScript

知识考点

AI 面试

面试题答案

一键面试
  1. 类型兼容性规则
    • 在TypeScript中,对于函数类型的兼容性,是基于参数和返回值的兼容性来判断的。
    • 对于函数参数,是基于逆变(contravariance)规则。即目标类型(这里是Fn2)的参数类型必须能接受源类型(这里是Fn1)的参数类型。
    • 对于函数返回值,是基于协变(covariance)规则。即源类型的返回值类型必须能赋值给目标类型的返回值类型。
  2. 分析返回值兼容性
    • Fn1<T extends { a: number }> = (arg: T) => T['a']; 的返回值类型是 T['a'],其中 T 约束为包含 a 属性且类型为 number
    • Fn2<T extends { a: number, b: string }> = (arg: T) => T['a']; 的返回值类型同样是 T['a'],其中 T 约束为包含 a 属性且类型为 number 以及 b 属性且类型为 string
    • 由于 Fn1Fn2 的返回值类型都是 number(因为 T['a'] 都是 number 类型),根据协变规则,Fn1 的返回值类型能赋值给 Fn2 的返回值类型。
  3. 分析参数兼容性
    • Fn1 的参数类型是 T,其中 T 只要求包含 a 属性且类型为 number
    • Fn2 的参数类型是 T,其中 T 要求包含 a 属性且类型为 number 以及 b 属性且类型为 string
    • 根据逆变规则,Fn1 的参数类型要能赋值给 Fn2 的参数类型。然而,Fn1 的参数类型可能不包含 b 属性,而 Fn2 的参数类型要求必须包含 b 属性。所以,Fn1 的参数类型不能赋值给 Fn2 的参数类型。
  4. 结论
    • 在严格的类型检查下(默认编译选项),Fn1 类型的函数不能赋值给 Fn2 类型的函数,因为函数参数类型不满足逆变规则。
    • 如果关闭严格的函数参数检查(例如设置 "strictFunctionTypes": false),那么 Fn1 类型的函数可以赋值给 Fn2 类型的函数,因为此时放宽了函数参数类型的逆变规则要求,只比较返回值类型,而它们的返回值类型是兼容的。