Problem
U must be an array. We know U is a value of P, but there is no guarantee that all values of P are arrays. That's because exec depends not on the concrete ICommandNameArgumentTypeMapping interface defined below, but on some P we don't fully know yet. And because we don't know it yet, we cannot trust it to follow the blueprint of ICommandNameArgumentTypeMapping โ after all, it might add some properties of its own which are not arrays.
Solution
The solution is to make sure all values โ present and future โ will always be arrays.
interface ICommandNameArgumentTypeMapping {
['cmd1']: [string];
['cmd2']: [boolean, number, string];
['cmd3']: [boolean, boolean];
[index: string]: any[]
}
That extra property is called index signature.
You can, of course, be more precise here and say (string | number | boolean)[] instead of any[].
Bonus points
There are a few more mistakes in your code:
- Computed property name
cmd2is duplicated - The
Ttype parameter is unused - The
Ptype parameter is incorrectly used (it is not used to describe parameters nor return types) execpromises to returnU, but it's returningundefined
The corrected solution:
function exec<P extends ICommandNameArgumentTypeMapping, E extends keyof P, U extends P[E]>(mapping: P, command: E, ...rest: U): U{
return rest;
}
interface ICommandNameArgumentTypeMapping {
['cmd1']: [string];
['cmd2']: [boolean, number, string];
['cmd3']: [boolean, boolean];
[index: string]: any[]
}
declare const mapping: ICommandNameArgumentTypeMapping;
exec(mapping, 'cmd2', true, 1, 'hello');
Answer from Karol Majewski on Stack OverflowStrongly typed rest parameters in TypeScript - Stack Overflow
How do you validate the request body and query parameters?
Question: Is there a away to forward parameters from one function to another?
typing rest/spread props in react components
Typescript thinks you have a property called 'restProps'. I think what you want is
interface RestProps {}
function Box ({ position, ...restProps }: { position: number } & RestProps {
...
} More on reddit.com Problem
U must be an array. We know U is a value of P, but there is no guarantee that all values of P are arrays. That's because exec depends not on the concrete ICommandNameArgumentTypeMapping interface defined below, but on some P we don't fully know yet. And because we don't know it yet, we cannot trust it to follow the blueprint of ICommandNameArgumentTypeMapping โ after all, it might add some properties of its own which are not arrays.
Solution
The solution is to make sure all values โ present and future โ will always be arrays.
interface ICommandNameArgumentTypeMapping {
['cmd1']: [string];
['cmd2']: [boolean, number, string];
['cmd3']: [boolean, boolean];
[index: string]: any[]
}
That extra property is called index signature.
You can, of course, be more precise here and say (string | number | boolean)[] instead of any[].
Bonus points
There are a few more mistakes in your code:
- Computed property name
cmd2is duplicated - The
Ttype parameter is unused - The
Ptype parameter is incorrectly used (it is not used to describe parameters nor return types) execpromises to returnU, but it's returningundefined
The corrected solution:
function exec<P extends ICommandNameArgumentTypeMapping, E extends keyof P, U extends P[E]>(mapping: P, command: E, ...rest: U): U{
return rest;
}
interface ICommandNameArgumentTypeMapping {
['cmd1']: [string];
['cmd2']: [boolean, number, string];
['cmd3']: [boolean, boolean];
[index: string]: any[]
}
declare const mapping: ICommandNameArgumentTypeMapping;
exec(mapping, 'cmd2', true, 1, 'hello');
The problem is P extends ICommandNameArgumentTypeMapping, which means that exec() accepts any mapping that is a superset of the interface you've defined. This would allow non-array types. If you remove that constraint (and fix what I assume is a typo), you get no error messages.
interface ICommandNameArgumentTypeMapping {
['cmd1']: [string];
['cmd2']: [boolean, number, string];
['cmd3']: [boolean, boolean];
}
type P = ICommandNameArgumentTypeMapping;
function exec<T, E extends keyof P, U extends P[E]>(command: E, ...rest: U): U{
return rest;
}
exec('cmd2', true, 1, 'hello');