gpt4 book ai didi

typescript - 为什么 typescript 枚举无助于推断联合类型

转载 作者:搜寻专家 更新时间:2023-10-30 21:49:10 27 4
gpt4 key购买 nike

我得到了以下类,这是简单的 pubsub 实现:

interface IAction<N, T> {
name: N,
data: T
}

export class Communicator<A extends IAction<any, any>> {

public subscribe(
subscriber: { name: A['name']; handler: (data: A['data']) => void; }
) {}

public emit(name: A['name'], data: A['data']): void {
}
}

然后我像这样使用它:

enum ActionName {
name1 = 'name1',
name2 = 'name2'
}

type ExampleActions
= { name: ActionName.name1, data: string }
| { name: ActionName.name2, data: number };

const communicator = new Communicator<ExampleActions>();

let a = '';

communicator.subscribe({
name: ActionName.name1,
/* Expected no error, but get
TS2345: Type 'number' is not assignable to type 'string'.*/
handler: data => a = data
});

/* Expected error Type 'string' is not assignable to type 'number',
but got no error*/
communicator.emit(ActionName.name2, 'string');

看起来 typescript 可能会通过具体的枚举推断出一种具体的 Action,但事实并非如此。这是一个错误,还是我应该做些不同的事情?

最佳答案

问题是 A 是联合类型,所以 A['data'] 将是 string | number(联合中的所有可能性)。也没有推断根据 A['name'] 的类型确定 data 的类型应该不同,其他两者之间没有关系它们是联合字段的所有可能类型。

如果你在 typescript 2.8 中使用条件类型(在撰写本文时尚未发布,但你可以在 npm install -g typescript@next 上获得它,你可以获得期望的结果,它将被发布三月)

// Helper type TActions will be a union of any number of actions 
// TName will be the name of the action we are intresed in
// We use filter, to filter out of TActions all actions that are not named TName
type ActionData<TActions extends IAction<string, any>, TName> =
Filter<TActions, IAction<TName, any>>['data'];

export class Communicator<A extends IAction<any, any>> {

public subscribe<K extends A['name']>(
subscriber: { name: K; handler: (data: ActionData<A, K>) => void; }
) {}

public emit<K extends A['name']>(name: K, data: ActionData<A,K>): void {
}
}
const communicator = new Communicator<ExampleActions>();

let a = '';

communicator.subscribe({ name: ActionName.name1, handler: d=> a = d}); // ok
communicator.subscribe({ name: ActionName.name2, handler: d=> a = d}); // erorr as it should be

communicator.emit(ActionName.name1, a); // ok
communicator.emit(ActionName.name2, a); // erorr as it should be

关于typescript - 为什么 typescript 枚举无助于推断联合类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48924733/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com