TypeScript如何将含可空类型的元组转换为非可空元组?
实现memoize函数的非可空元组类型推导问题
我要实现一个memoize函数用于缓存传入函数的返回值,当前代码如下:
const memoize = (value, onHandle) => { for (let index = 0; index < value.length; index++) { if (value[index] === null || value[index] === undefined) { return } } // 检查是否存在相同参数的缓存值 return onHandle(value) }
回调函数onHandle接收非可空值元组,返回将被缓存的值。我需要声明一个类型工具,把包含可空类型的元组转换为仅含非可空类型的元组,示例如下:
type Tuple = [number | undefined, string, boolean, string | undefined] type StrictTuple = [number, string, boolean, string]
我尝试了多次都没成功,以下是失败的尝试代码:
尝试1:错误保留原可空类型
type StrictTuple<T extends [unknown, ...unknown[]]> = T extends [ unknown, ...unknown[] ] ? T[number] extends null | undefined ? never : T[number] extends infer U ? U extends null | undefined ? never : T : never : never; type Example1 = StrictTuple<[1 | undefined, 2, "3", true | null, boolean]> // 结果:[1 | undefined, 2, "3", true | null, boolean](未移除可空类型)
尝试2:错误将元组转为同类型数组的联合
type StrictTuple<T extends [E, ...E[]], E = unknown> = T[number] extends infer U ? U extends null | undefined ? never : [U, ...U[]]: never type Example2 = StrictTuple<[1, 2, "3", boolean, number | undefined]> // 结果:[number, ...number[]] | [false, ...false[]] | [true, ...true[]] | ["3", ..."3"[]](不符合元组结构)
请问有没有方法生成仅含非可空值的元组类型?
解决方案:递归遍历元组元素移除可空类型
可以通过递归遍历元组的每个元素,逐个移除null和undefined类型,同时保留元组的结构:
type NonNullableTuple<T extends readonly unknown[]> = T extends [infer First, ...infer Rest] ? [NonNullable<First>, ...NonNullableTuple<Rest>] : []; // 测试示例 type Tuple = [number | undefined, string, boolean, string | undefined] type StrictTuple = NonNullableTuple<Tuple>; // 结果:[number, string, boolean, string](符合预期) type Example1 = NonNullableTuple<[1 | undefined, 2, "3", true | null, boolean]>; // 结果:[1, 2, "3", true, boolean](正确移除可空类型)
给memoize函数添加完整类型声明
结合上面的类型工具,给memoize函数加上类型,确保只有当传入的元组所有元素非空时,才会调用onHandle:
type NonNullableTuple<T extends readonly unknown[]> = T extends [infer First, ...infer Rest] ? [NonNullable<First>, ...NonNullableTuple<Rest>] : []; const memoize = <T extends readonly unknown[]>( value: T, onHandle: (args: NonNullableTuple<T>) => unknown ): unknown | undefined => { for (let index = 0; index < value.length; index++) { if (value[index] === null || value[index] === undefined) { return } } // 类型断言:此时value的所有元素都非空,符合NonNullableTuple<T> return onHandle(value as NonNullableTuple<T>) } // 测试使用 memoize([1, "test", true], (args) => { // args类型为[number, string, boolean] console.log(args[0].toFixed(2)); // 正常调用number方法 }) memoize([1, undefined, true], (args) => { // 这里不会触发,因为函数会提前return })
内容的提问来源于stack exchange,提问作者nw.lee
相关产品推荐
相关产品推荐

