我对打字稿中的泛型很陌生,这很令人困惑
有没有办法让
spread operator ...
在下面的代码片段中工作
问题
这条线
[ key: U, ...rest: Reg[U] ]
,没有像我预期的那样工作
问题
我做错了什么?
我试图让这项工作成功,但失败了
我还没有尝试过的可能解决方案
函数重载
type Registery = {
"item.1": [name: string]
"item.2": [id: number, ready: "Y" | "N"]
"item.3": [ok: boolean]
}
type ReK = keyof Registery
const send = <
T extends ReK | ReK[] | "*" | never = never
>(
key: T,
callback: (
...args:
T extends Array<infer U>
? (
U extends ReK
? [ key: U, ...rest: Registery[U] ]
: never
)
: T extends string
? (
T extends ReK
? Registery[T]
: T extends "*"
? Registery[ReK]
: never
)
: never
) => any
) => { /** */ }
send("item.2", (...args) => {
const [
arg1,
//^?const arg1: number
arg2,
//^?const arg2: "Y" | "N"
] = args
})
send(["item.1", "item.2"], (key, ...args) => {
// ^?
const k = key
// ^?const k: "item.1" | "item.2"
if (key == "item.1") {
const [
arg1,
//^?const arg1: string | number
arg2,
//^?const arg1: string | number
] = args
}
if (key == "item.2") {
const [
arg1,
//^?const arg1: string | number
arg2,
//^?const arg2: string | number
] = args
}
})
这是 ts Playground 的链接 https://tsplay.dev/mxEQ7W
你的类型没问题。问题是,当使用“rest 属性”进行解构时,TypeScript 不支持“解构可区分联合”。 microsoft/TypeScript#46680 有一个开放的功能请求来支持这一点,但在实现之前,您必须解决它。 你所做的相当于
type ParamUnion =
[key: "item.1", name: string] |
[key: "item.2", id: number, ready: "Y" | "N"];
const f: (...args: ParamUnion) => any =
(key, ...rest) => {
if (key === "item.1") {
rest[0].toUpperCase(); // error!
} else {
rest[0].toFixed(); // error!
}
};
其中
ParamUnion
是元组类型
的
可判别联合,其中第一个元素是判别式。 这正是您遇到的问题,没有提及泛型或
T | T[] | "*"
或[ key: U, ...rest: Reg[U] ]
。那东西很有趣,但本质上是一个“红鲱鱼”。
解决此问题的一种方法是在将
ParamUnion
类型解构分配到参数中时不使用剩余元素:
const g: (...args: ParamUnion) => any =
(key, nameOrId, ready?) => {
if (key === "item.1") {
nameOrId.toUpperCase(); // okay
} else {
nameOrId.toFixed(); // okay
}
};
解决此问题的另一种方法是根本不解构其余元素,而只需使用
rest 参数:
const h: (...args: ParamUnion) => any =
(...args) => {
if (args[0] === "item.1") {
args[1].toUpperCase(); // okay
} else {
args[1].toFixed(); // okay
}
};
Playground 代码链接