TypeScript中as const意外取数组交集导致类型报错问题
TypeScript中as const导致includes类型错误的解决方案
当对硬编码数组使用as const断言后,在filter回调中调用i.foo.includes(3)会触发类型错误:Argument of type '3' is not assignable to parameter of type '2'.(2345),示例代码如下:
const data = [ { foo: [1, 2], }, { foo: [2, 3], }, ] as const; const result = data.filter((i) => { return i.foo.includes(3); // 类型错误 });
错误原因
as const会让TypeScript将数组推断为只读元组类型:第一个元素的foo类型是readonly [1, 2],第二个是readonly [2, 3]。数组的includes方法会基于元组元素类型约束参数:readonly [1,2]的includes只接受1或2,readonly [2,3]的includes只接受2或3。当i.foo是这两个元组的联合类型时,TypeScript会取两个includes参数类型的交集(也就是2),因此传入3会触发类型错误。
解决方案(无需放弃as const类型守卫)
方案1:自定义类型安全的includes辅助函数
编写通用函数,提取元组的所有可能值作为参数类型,既保证类型安全,又避开联合类型的限制:
const data = [ { foo: [1, 2], }, { foo: [2, 3], }, ] as const; // 提取元组的所有元素类型 type ValueOf<T> = T[keyof T]; function includes<T extends readonly unknown[]>(arr: T, val: ValueOf<T>): boolean { return (arr as readonly unknown[]).includes(val); } const result = data.filter((i) => { return includes(i.foo, 3); // 类型合法,且仅允许传入1/2/3 });
方案2:使用类型谓词实现精确类型推断
如果需要让result的类型精确到只包含foo含3的元素,可以用类型谓词:
const data = [ { foo: [1, 2], }, { foo: [2, 3], }, ] as const; // 定义包含目标值的元素类型 type HasFoo3 = typeof data[number] & { foo: readonly [2, 3] }; function hasFoo3(item: typeof data[number]): item is HasFoo3 { return item.foo.includes(3 as const); } const result = data.filter(hasFoo3); // result的类型被精确推断为readonly [{ foo: readonly [2, 3] }]
内容的提问来源于stack exchange,提问作者ZYinMD
相关产品推荐
相关产品推荐

