为何TypeScript无法识别数组元素的位置与类型?求实现方案
TypeScript函数类型与参数类型不匹配问题解决
我想要创建一个包含问题文本、关联执行函数及对应参数的对象数组,代码运行结果符合预期,但TypeScript无法正确识别函数的类型与参数类型,出现了报错,需要找出原因并解决这个问题。
代码示例
type Digit = 0|1|2|3|4|5|6|7|8|9; const Color = { red: 0, black: 1, } as const; type Color = typeof Color[keyof typeof Color]; type Code = { value: Digit, color: Color } function countOfEven(codes: Code[]): number { return codes.filter((code) => code.value % 2 === 0).length; } function countOfColor(codes: Code[], color: Color): number { return codes.filter((code) => code.color === color).length; } let code: Code [] = [ { value: 1, color: Color.black }, { value: 2, color: Color.red } ] const questions = [ { body: "有多少个偶数?", action: countOfEven, }, { body: "有多少个红色数字?", action: countOfColor, args: Color.red }] let question1 = questions.at(0) let question2 = questions.at(1); console.log(question1?.body,question1?.action(code)) // error! // ~~~~~~ // Expected 2 arguments, but got 1. console.log(question2?.body,question2?.action(code,question2.args)) // error! // ~~~~~~~~~~~~~~ // Argument of type '0 | undefined' is not assignable to parameter of type 'Color'. // Type 'undefined' is not assignable to type 'Color'.
报错原因
- 函数联合类型的调用限制:TypeScript对
questions数组的类型推断会合并两个元素的类型,导致action被推断为typeof countOfEven | typeof countOfColor。联合类型的函数调用必须满足所有分支的参数要求(即必须传入countOfColor所需的两个参数),因此调用question1?.action(code)时只传一个参数会触发报错。 - 参数可能为undefined:数组中第一个元素没有
args属性,TypeScript会推断question2.args的类型为Color | undefined,但countOfColor的第二个参数要求是严格的Color类型,不允许undefined,因此传参时类型不匹配。
解决方案
有两种常见的解决思路,都能让TypeScript正确识别函数和参数类型:
思路一:泛型统一约束参数与函数
通过泛型定义Question类型,让函数的参数类型和args属性类型严格绑定,调用时展开args数组即可:
// 泛型类型:Args对应函数的剩余参数列表 type Question<Args extends any[]> = { body: string; action: (...args: Args) => number; args: Args; // 确保每个问题都有对应的参数数组 }; const questions: (Question<[Code[]]> | Question<[Code[], Color]>)[] = [ { body: "有多少个偶数?", action: countOfEven, args: [code] }, { body: "有多少个红色数字?", action: countOfColor, args: [code, Color.red] } ]; const question1 = questions.at(0); const question2 = questions.at(1); // 直接展开args调用,类型完全匹配 console.log(question1?.body, question1?.action(...question1.args)); console.log(question2?.body, question2?.action(...question2.args));
思路二:定义不同类型的问题联合
针对不同参数结构的函数,分别定义对应的问题类型,再组成联合类型,调用时通过类型守卫区分:
// 无额外参数的问题类型 type QuestionNoExtraArg = { body: string; action: (codes: Code[]) => number; }; // 带颜色参数的问题类型 type QuestionWithColorArg = { body: string; action: (codes: Code[], color: Color) => number; args: Color; }; // 数组类型为两种问题的联合 const questions: (QuestionNoExtraArg | QuestionWithColorArg)[] = [ { body: "有多少个偶数?", action: countOfEven, }, { body: "有多少个红色数字?", action: countOfColor, args: Color.red } ]; const question1 = questions.at(0); const question2 = questions.at(1); // 用类型守卫判断类型后调用 if (question1 && !('args' in question1)) { console.log(question1.body, question1.action(code)); } if (question2 && 'args' in question2) { console.log(question2.body, question2.action(code, question2.args)); }
内容的提问来源于stack exchange,提问作者Krasimir Petrov
相关产品推荐
相关产品推荐

