网站搜索

typescript - TS - 如何在此代码中捕获错误而不使用类型断言


我有以下代码,它是正确的,但维护起来比较棘手...

interface FuncContainer<F extends (..._: Array<any>) => any> {
  func: F
  args: Parameters<F>
}

const func: FuncContainer<typeof Math.min> = {
  func: Math.min,
  args: [3, 4]
}

console.log(func.func(...func.args))


const funcs: Array<FuncContainer<(..._: Array<any>) => any>> = [
  {
    func: Math.min,
    args: [1, 2]
  } as FuncContainer<typeof Math.min>,
  {
    func: fetch,
    args: ["https://google.com"]
  } as FuncContainer<typeof fetch>
]

console.log(funcs)

这段代码可以编译而不会报错。然而,问题出现在我有 Array<FuncContainer> 的时候。我希望能够在一个数组中放入不同参数签名的不同函数,因此我让函数变成了泛型。我还希望 TS 能确保每个数组元素内部的类型是一致的。为此,我在每个单独的数组元素中都有类型断言,但这容易出错,因为如果有人忘记在新的元素添加到 Array<FuncContainer> 时添加类型断言,是不会有警告的。如果没有类型断言,参数类型的错误将不会被捕获。

const funcs2: Array<FuncContainer<(..._: Array<any>) => any>> = [
  {
    func: Math.min,
    args: ["5", "6"] // should error, but doesn't
  }
]

有没有一种方法可以对数组进行注解,使每个数组元素在每个数组位置上都进行具体类型的类型检查,但不需要像这个代码片段那样手动进行类型断言?可能可以通过映射类型的某种方法吗?

编辑:将 unknown 改为 any,以便在游乐场中使用

答案#1

从开发体验的角度来看,这种事情最容易通过函数助手来完成:

function funcContainer<F extends (...args: any[]) => any>(func: F, args: Parameters<F>) {
    return {func, args};
}

const funcs = [
    funcContainer(Math.min, [1, 2]),
    funcContainer(fetch, ["https://google.com"]),
    funcContainer(Math.min, ["x"]), // <== Error as desired
];

console.log(funcs);

游乐场链接

不仅在参数列表中获得类型安全,还可以在任何从 TypeScript 获取信息的 IDE(如 VS Code)中获得参数建议:

答案#2

在 @T.J. Crowder 的回答基础上:这里有一个只需要一个通用函数的解决方案。

function createFuncs<
  F extends ((...args: any[]) => any)[]
>(funcs: [...{ [K in keyof F]: [F[K], Parameters<F[K]>] }]) {
    return funcs;
}

const funcs = createFuncs([
    [Math.min, [1, 2]],
    [fetch, ["https://google.com"]],
    [Math.min, ["x"]], // <== Error as desired
]);

操场