TypeScript函数参数类型兼容问题:includes方法类型报错求助
问题:TypeScript泛型函数类型收窄失效问题
我定义了一个参数类型需与对象属性及值兼容的泛型函数:
type MyFunction = <T extends keyof typeof myObject>( name: T, value: (typeof myObject)[T][number] ) => void; const myObject = { strings: ["one", "two"], numbers: [1, 2], }; const myFunction: MyFunction = (name, value) => { if (!myObject[name].includes(value)) { // do something ^^^^^ } };
此时value处出现报错:
Argument of type 'string | number' is not assignable to parameter of type 'never'. Type 'string' is not assignable to type 'never'.
我理解TypeScript的报错原因,但即使为name添加switch分支判断:
const myFunction: MyFunction = (name, value) => { switch (name) { case "strings": { if (!myObject[name].includes(value)) { // do something ^^^^^ } break; } } };
仍会出现相同错误,请问我哪里考虑不周?
解答
问题核心在于泛型函数内部的类型收窄无法联动泛型参数。你通过switch把name收窄到"strings"后,TypeScript没办法将这个具体值和函数级别的泛型T绑定,自然也无法推断出value此时对应的具体类型。
可以用两种方法解决:
方法1:手动类型断言
在分支内明确断言value与当前数组的元素类型匹配:
const myFunction: MyFunction = (name, value) => { switch (name) { case "strings": { if (!myObject[name].includes(value as (typeof myObject["strings"])[number])) { // do something } break; } case "numbers": { if (!myObject[name].includes(value as (typeof myObject["numbers"])[number])) { // do something } break; } } };
方法2:用函数重载替代泛型
放弃泛型定义,改用函数重载明确每个参数组合的类型:
const myObject = { strings: ["one", "two"], numbers: [1, 2], }; function myFunction(name: "strings", value: string): void; function myFunction(name: "numbers", value: number): void; function myFunction(name: keyof typeof myObject, value: string | number) { switch (name) { case "strings": { if (!myObject[name].includes(value)) { // do something } break; } case "numbers": { if (!myObject[name].includes(value)) { // do something } break; } } }
这种方式下,TypeScript能完美识别每个分支中value的具体类型,不会再出现类型不兼容的报错。
内容的提问来源于stack exchange,提问作者devatina11yb
相关产品推荐
相关产品推荐

