TypeScript中的强类型rest参数

TypeScript中的强类型rest参数,typescript,typescript-generics,Typescript,Typescript Generics,如何使用TypeScript 3.2定义动态强类型rest参数? 以下是我的用例: 函数exec(命令:E,…rest:U):U{ 返回; } exec('cmd2',true,1',hello'); 接口ICommandNameArgumentTypeMapping{ ['cmd1']:[string]; ['cmd2']:[boolean,number,string]; ['cmd2']:[boolean,boolean]; } 在这一点上,一切似乎都起了作用。 当使用cmd2为exec编

如何使用TypeScript 3.2定义动态强类型rest参数? 以下是我的用例:

函数exec(命令:E,…rest:U):U{
返回;
}
exec('cmd2',true,1',hello');
接口ICommandNameArgumentTypeMapping{
['cmd1']:[string];
['cmd2']:[boolean,number,string];
['cmd2']:[boolean,boolean];
}
在这一点上,一切似乎都起了作用。 当使用
cmd2
exec
编写参数时,我可以看到编译器(typescript)为3个参数提供键入信息。 返回值也是正确的

但是,在包含rest参数的声明
…rest:U
的行中,事情就结束了

错误很简单:
rest参数必须是数组类型。

在写入
…rest
时,
rest
是数组:

constsomefunction=(…args)=>console.log(args);

someFunction('hello','world')在编写
…rest
时,
rest
是一个数组:

constsomefunction=(…args)=>console.log(args);

someFunction('hello','world')问题是
p扩展了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');
接口ICommandNameArgumentTypeMapping{
['cmd1']:[string];
['cmd2']:[boolean,number,string];
['cmd3']:[boolean,boolean];
}
类型P=ICommandNameArgumentTypeMapping;
函数exec(命令:E,…rest:U):U{
返回休息;
}
exec('cmd2',true,1',hello');

问题是
p扩展了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');
接口ICommandNameArgumentTypeMapping{
['cmd1']:[string];
['cmd2']:[boolean,number,string];
['cmd3']:[boolean,boolean];
}
类型P=ICommandNameArgumentTypeMapping;
函数exec(命令:E,…rest:U):U{
返回休息;
}
exec('cmd2',true,1',hello');

问题

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
    type参数未使用
  • P
    type参数使用不正确(它既不用于描述参数,也不用于返回类型)
  • exec
    承诺返回
    U
    ,但它返回
    未定义的
正确的解决方案:

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');
函数exec(映射:P,命令:E,…rest:U):U{
返回休息;
}
接口ICommandNameArgumentTypeMapping{
['cmd1']:[string];
['cmd2']:[boolean,number,string];
['cmd3']:[boolean,boolean];
[索引:字符串]:任意[]
}
声明常量映射:ICommandNameArgumentTypeMapping;
exec(映射为'cmd2',true,1',hello');

问题

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
    type参数未使用
  • P
    type参数使用不正确(它既不用于描述参数,也不用于返回类型)
  • exec
    承诺返回
    U
    ,但它返回
    未定义的
正确的解决方案:

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');
函数exec(映射:P,命令:E,…rest:U):U{
返回休息;
}
接口ICommandNameArgumentTypeMapping{
['cmd1']:[string];
['cmd2']:[boolean,number,string];
['cmd3']:[boolean,boolean];
[索引:字符串]:任意[]
}
声明常量映射:ICommandNameArgumentTypeMapping;
exec(映射为'cmd2',true,1',hello');