TypeScript 中的强类型剩余参数
Posted
技术标签:
【中文标题】TypeScript 中的强类型剩余参数【英文标题】:Strongly typed rest parameters in TypeScript 【发布时间】:2019-08-02 09:45:47 【问题描述】:如何使用 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];
此时似乎一切正常。
当用cmd2
为exec
编写参数时,我可以看到编译器(打字稿)提供了3 个参数的输入信息。
返回值也是正确的……
但是,在包含声明 ...rest: U
的其余参数的行中,事情发生了变化。
错误很简单:
A rest parameter must be of an array type.
【问题讨论】:
【参考方案1】:写...rest
时,rest
是一个数组:
const someFunction = (...args) => console.log(args);
someFunction('hello', 'world');
因此你应该写:
(command: E, ...rest: U[])
或任何适合您程序所需行为的类似内容。
【讨论】:
【参考方案2】:问题是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');
【讨论】:
【参考方案3】:问题
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');
【讨论】:
以上是关于TypeScript 中的强类型剩余参数的主要内容,如果未能解决你的问题,请参考以下文章