Задача
U
должен быть массивом. Мы знаем, что U
является значением P
, но нет никакой гарантии, что все значения P
являются массивами. Это потому, что exec
зависит не от конкретного интерфейса ICommandNameArgumentTypeMapping
, определенного ниже, а от некоторых P
, которые мы еще не знаем полностью. И поскольку мы еще этого не знаем, мы не можем доверять ему, чтобы он следовал плану ICommandNameArgumentTypeMapping
- в конце концов, он мог бы добавить некоторые свои собственные свойства, которые не являются массивами.
Решение
Решение состоит в том, чтобы все значения - настоящие и будущие - всегда были массивами.
interface ICommandNameArgumentTypeMapping {
['cmd1']: [string];
['cmd2']: [boolean, number, string];
['cmd3']: [boolean, boolean];
[index: string]: any[]
}
Это дополнительное свойство называется подпись индекса .
Вы можете, конечно, быть более точным здесь и сказать (string | number | boolean)[]
вместо any[]
.
Бонусные баллы
В вашем коде есть еще несколько ошибок:
- Имя вычисляемого свойства
cmd2
дублируется
- Параметр типа
T
не используется
- Параметр типа
P
используется неправильно (он не используется для описания параметров или типов возврата)
exec
обещает вернуть U
, но возвращается undefined
Исправленное решение:
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');