我正在使用一个定义了以下类型的库:
type VoidableCallback<EventValue> = EventValue extends void ? () => void : (val: EventValue) => void;
Run Code Online (Sandbox Code Playgroud)
该库公开了一个返回上述类型的函数:
declare function fn<T>(): VoidableCallback<T>;
Run Code Online (Sandbox Code Playgroud)
我想将此函数与受歧视的联合一起使用:
type Action = { type: 'add'; n: number } | { type: 'multiply'; n: number };
const callback = fn<Action>();
callback({ type: 'add', n: 1 });
Run Code Online (Sandbox Code Playgroud)
然而 Typescript (3.4.1) 给了我这个错误消息:
类型“add”不可分配给类型“add”和“multiply”。类型“add”不可分配给类型“multiply”。ts(2322)
预期的类型来自属性“type”,该属性在类型“{ type: "add"; ”上声明。n:数量;} & { 类型:“乘”;n:数量;}'
我不明白这是为什么 - 似乎总和(联合)类型被解释为“产品”类型。
如果我将类型定义更改为:
type VoidableCallback<EventValue> = (val: EventValue) => void;
Run Code Online (Sandbox Code Playgroud)
... Typescript 不会抱怨。所以这与条件类型和联合类型有关。
如果可以理解这里发生了什么,那么也许我可以向库(rxjs-hooks)做一个 PR。
这是由条件类型的分配行为引起的。条件类型分布在裸类型参数上。这意味着如果类型参数包含联合,则条件类型将应用于联合的每个成员,并且结果将是所有应用程序的联合。因此,在您的情况下,我们会得到您可以在此处VoidableCallback<{ type: 'add'; n: number } | { type: 'multiply'; n: number }> = VoidableCallback<{ type: 'add'; n: number }> | VoidableCallback<{ type: 'multiply'; n: number }> = ((val: { type: 'add'; n: number }) => void) | ((val: { type: 'multiply'; n: number }) => void)阅读有关此行为的信息
您收到有关交集的错误的原因是打字稿处理函数签名联合的方式,它基本上要求参数与联合中的所有签名兼容,因此参数必须是所有可能参数类型的交集。您可以在这里阅读相关内容
简单的解决方案是禁用条件类型的分发。通过将类型参数放入元组中可以轻松完成此操作:
type VoidableCallback<EventValue> = [EventValue] extends [void] ? () => void : (val: EventValue) => void;
type Action = { type: 'add'; n: number } | { type: 'multiply'; n: number };
declare function fn<T>(): VoidableCallback<T>;
const callback = fn<Action>();
callback({ type: 'add', n: 1 }); //ok now
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4862 次 |
| 最近记录: |