题目
实现一个 If 类型,它接收一个条件类型 C ,一个判断为真时的返回类型 T ,以及一个判断为假时的返回类型 F。 C 只能是 true 或者 false, T 和 F 可以是任意类型。
例如:
// 返回类型 'a'
type A = If<true, 'a', 'b'>
// 返回类型 'b'
type B = If<false, 'a', 'b'>
原题链接
思路
类比 JavaScript
类比 JavaScript,就是实现一个函数:
这个函数接收 3 个参数,第一个是布尔值,第二个是真值,第三个是假值。当布尔值为真时返回真值,当布尔值为假时返回假值。
function myIf(myBool, T, F) {
if (Object.prototype.toString.call(myBool) !== '[object Boolean]') {
throw new TypeError('第 1 个参数必须是布尔类型!');
}
return myBool ? T : F;
}
提取逻辑点
1. 约束第 1 个参数必须是布尔类型,如果不是就抛出错误。
2. 如果第 1 个参数是 true 就返回 T, 是 false 就返回 F。
再把逻辑点翻译成 TypeScript 即可。
翻译成 TypeScript
约束第 1 个参数必须是布尔类型,如果不是就抛出错误
通过 extends 来约束类型:
type If<C extends boolean,T,U> = ...
如果第 1 个参数是 true 就返回 T,是 false 就返回 F
通过 extends 检查是否为 true, 通过三元运算符实现逻辑分支:
type If<C extends boolean,T,U> = C extends true ? T : U;
类型兼容性引发的错误
但是在TS的非严格模式下,有一个测试用例没有通过:
// @ts-expect-error
type error = If<null, 'a', 'b'>
// 期待报错而没有报错,本测试用例不通过❌
这个测试用例是将一个 null 传了进去,而 If 的 T 是明确声明 extends 自 boolean 的,没有报错说明 null 可以赋值给 boolean 类型,这是不对的。
这时就要提到类型兼容性的问题,在 TS 的非严格模式下,null 是可以赋值给 boolean 类型的,查看TS类型兼容性文档获取详细信息。
所以,这里把 TS 的严格模式打开即可,打开 tsconfig.json 文件,在 compilerOptions 选项中设置 strictNullChecks 为 true。
当然,要保证总开关 compilerOptions.strict 为 true。
实现
综上所述,最终的类型工具 If 实现为:
type If<C extends boolean,T,U> = C extends true ? T : U;