In the example below, I would like to mandate that all functions should return in a specific format [string, number]
, but input arguments for those functions can vary.
type ReturnFormat = [string, number]
type Fn = (...args: any[]) => ReturnFormat
const A: Fn = () => ['one', 1]
const B: Fn = (input: number) => ['two', input]
type C = Parameters<typeof A>
type D = Parameters<typeof B>
However, when I try to read back the parameters of the function, both C
and D
are any[]
, and not null
and input: number
. What should I do to make that happen?
CodePudding user response:
The problem here is that you are declaring the variables A
and B
with the type Fn
. The type Fn
only knows that the arguments should be of type ...any[]
. So when you use this type to declare variables, any specific information about the actual functions you used for the assignment is lost.
You should instead use a generic function to initialise the functions.
function createFunction<T extends Fn>(fn: T) { return fn }
We can constrain the passed function T
to be of type Fn
, but we still return a function of the original type T
.
When we use this function to create the two variables, you will see that the type information is preserved.
const a = createFunction(() => ['one', 1])
// const a: () => [string, number]
const b = createFunction((input: number) => ['two', input])
// const b: (input: number) => [string, number]
const c = createFunction((input: number) => ['two']) // Error: We broke the constaint!
A second option would be to make Fn
generic. But we would have to explicitely give the parameter type to Fn
everytime we use it to declare a function.
type Fn<T extends any[] = void[]> = (...args: T) => ReturnFormat
const a: Fn = () => ['one', 1]
const b: Fn<[number]> = (input: number) => ['two', input]