作者热门文章
- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我得到了以下类,这是简单的 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/
我是一名优秀的程序员,十分优秀!