Строго типизированные параметры отдыха в TypeScript - PullRequest
0 голосов
/ 12 марта 2019

Как определить параметры динамического строго типизированного отдыха с помощью TypeScript 3.2?Вот мой пример использования:

function exec<T, P extends ICommandNameArgumentTypeMapping, E extends keyof P, U extends P[E]>(command: E, ...rest: U): U{
    return;
}

exec('cmd2', true, 1, 'hello');

interface ICommandNameArgumentTypeMapping {
    ['cmd1']: [string];
    ['cmd2']: [boolean, number, string];
    ['cmd2']: [boolean, boolean];
}

На данный момент, кажется, все работает.Когда я пишу аргументы для exec с cmd2, я вижу компилятор (машинопись), предоставляющий информацию о типе для 3 аргументов.Возвращаемое значение также является правильным ...

Однако все падает в строке, содержащей объявление ...rest: U для остальных параметров.

Ошибка проста: A rest parameter must be of an array type.

Ответы [ 3 ]

2 голосов
/ 12 марта 2019

Задача

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');
1 голос
/ 12 марта 2019

Проблема в P extends ICommandNameArgumentTypeMapping, что означает, что exec() принимает любое сопоставление, являющееся надмножеством интерфейса, который вы определили.Это позволило бы не-массив типов.Если вы удалите это ограничение (и исправите то, что я считаю опечаткой), вы не получите сообщений об ошибках.

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');
0 голосов
/ 12 марта 2019

При записи ...rest, rest - это массив:

const someFunction = (...args) => console.log(args);

someFunction('hello', 'world');

Вы должны вместо этого написать:

(command: E, ...rest: U[])

Или что-нибудь подобное, подходящее вашей программе.

...