Home > Back-end >  TS - How to catch errors without type assertions in this code
TS - How to catch errors without type assertions in this code

Time:09-10

I have the following code, which is correct but is tricky to maintain...

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)

This compiles without errors. However, he problem is when I have Array<FuncContainer>. I want to be able to put different functions with different param signatures in 1 array, so I made the function generic. I also want TS to ensure that the types within each array element are consistent. To do that, I have type assertions inside each individual array element, but that is error-prone as there is no warning if someone forgets to add the type assertion to a new element to an Array<FuncContainer>. Without it, incorrect types for the args won't be caught.

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

Is there a way to annotate the array so that each array element is type-checked for the concrete type within each array position, but doesn't require manual type assertions like this code snippet? Maybe some way with mapped types?

EDIT: changed unknown to any so it works in the playground

CodePudding user response:

To build on @T.J. Crowder's answer: Here is a solution which only requires a single generic function.

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
]);

enter image description here

  • Related