我定义了以下函数:

function someFunc<T extends any[]>(callback: (...args: T) => void, params: T) {}

但当我调用它时,TypeScrip的行为并不像我预期的那样:

// this works
// hovering over a, b, and c reveals that they're numbers
someFunc((a, b, c) => {}, [1, 2, 3]);
// this doesn't work
// hovering over a, b, and c reveals that they're of type `number | string`
someFunc((a, b, c) => {}, [1, '2', 3]);

我认为我的解决方案的问题在于,TypeScrip将someFunc的第二个参数解释为数组而不是元组,因此结果类型要么是相同类型的数组,如number[],要么是联合类型(number | string)[]的array.

如何确保每个参数的类型对应于参数元组中的相应类型?

推荐答案

TypeScrip类型推断根据各种启发式规则进行操作;当面对像[1, '2', 3]这样的array literal时,编译器通常会推断出像(string | number)[]这样的任意长度的无序数组类型.但在本例中,您需要具有已知顺序和长度的tuple type[number, string, number].

向编译器提示您更喜欢元组类型的一种方法是将类型包装在variadic tuple type中,如[...+].根据microsoft/TypeScript#39094,引入可变元组类型的PR,"类型[...T],其中T是类似数组的类型参数,可以方便地用于指示对元组类型的推断的偏好."

因此,让我们做出改变:

function someFunc<T extends any[]>(
  callback: (...args: T) => void,
  params: [...T]) { }

现在我们试一试:

someFunc((a, b, c) => {
  console.log(a - 0, b - 1, c - 2)
}, [1, 2, 3]);

someFunc((a, b, c) => {
  console.log(a - 0, b.length, c - 2)
}, [1, '2', 3]);

看上go 不错.编译器现在知道第二个回调中的bstring,而ac是数字.

Playground link to code

Typescript相关问答推荐

如何将单元测试中的私有订阅变量设置为空(或未定义)?

带有联合参数的静态大小数组

属性的类型,该属性是类的键,其值是所需类型

具有动态键的泛型类型

如何在单击停止录制按钮后停用摄像机?(使用React.js和Reaction-Media-Recorder)

不推荐使用Marker类-Google map API警告

访问继承接口的属性时在html中出错.角形

如何使用类型谓词将类型限制为不可赋值的类型?

表单嵌套太深

常量类型参数回退类型

在Mac和Windows上运行的Web应用程序出现这种对齐差异的原因是什么?(ReactNative)

在TypeScript中扩展重载方法时出现问题

如何使用angular15取消选中位于其他组件中的复选框

有没有更干净的方法来更新**key of T**的值?

T的typeof键的Typescript定义

是否使用类型将方法动态添加到类?

带动态键的 TS 功能

如何在由函数参数推断的记录类型中具有多个对象字段类型

从 npm 切换到 pnpm 后出现Typescript 错误

在Nestjs中,向模块提供抽象类无法正常工作