[英]Infer does not work in generics as second param
does anyone know why in the second case the infer does not display the desired type?有谁知道为什么在第二种情况下推断不显示所需的类型?
type Emmit<C extends Controller<any, any>> = C extends Controller<infer T, any> ? T : never
type On<C extends Controller<any, any>> = C extends Controller<infer E, infer O> ? O : never
type E = BaseEvent<"a", 1> | BaseEvent<"b", 2>
type O = BaseEvent<"c", 3> | BaseEvent<"d", 4>
class A extends Controller<E, O> {
}
type a = Emmit<A> // BaseEvent<"a", 1> | BaseEvent<"b", 2>;
type b = On<A>; // BaseEvent<string, any>
Extending this answer, the type inference for generics in class is done扩展此答案,class 中 generics 的类型推断已完成
The type of the first generic is inferred correctly inferred from the parameter of the method emit
which will be BaseEvent<"a", 1> | BaseEvent<"b", 2>
第一个泛型的类型是从方法
emit
的参数中正确推断出来的,该参数将是BaseEvent<"a", 1> | BaseEvent<"b", 2>
BaseEvent<"a", 1> | BaseEvent<"b", 2>
in case of class A
. BaseEvent<"a", 1> | BaseEvent<"b", 2>
在 class A
的情况下。
But for the second generic, OnEvent
is used in on
method only, which is again a generic and will not be inferred until on
is called.但是对于第二个泛型,
OnEvent
仅在on
方法中使用,这又是一个泛型,在调用on
之前不会被推断。 So the TS is not able to infer the correct type.因此 TS 无法推断出正确的类型。 It is only inferring the constraining type ie
BaseEvent
or BaseEvent<string, any>
.它只是推断约束类型,即
BaseEvent
或BaseEvent<string, any>
。
Even if you change on
method to-即使您将方法更改
on
-
on(
event: EventType<OnEvent>,
listener: OnListener<EventPayloadByType<EventType<OnEvent>, OnEvent>>
): void {
this.emitter.on(event, listener);
}
it will not infer correctly, as the type information OnEvent
is not stored as it is but with computed types using EventType
and OnListener
which is, I think, out of the capability of TS as of now.它不会正确推断,因为类型信息
OnEvent
不是按原样存储的,而是使用EventType
和OnListener
的计算类型存储的,我认为,到目前为止,这超出了 TS 的能力。
Best solution that I can think of is adding a dummy property like private _dummy:: OnEvent
我能想到的最佳解决方案是添加一个虚拟属性,如
private _dummy:: OnEvent
declare class EventEmitter {
emit(t: string, p: any): void
on(e: string, f: Function): void
}
export interface BaseEvent<Type extends string = string, Payload = any> {
typ: Type,
payload: Payload
}
export type EventType<Event extends BaseEvent> = Event extends BaseEvent<infer Type>
? Type
: string
export type EventPayloadByType<
Type extends string,
Event extends BaseEvent
> =
Event extends BaseEvent<Type, infer Payload>
? Payload
: never
export type OnListener<Payload = any> = (payload: Payload) => void;
export class Emitter<EmmitEvent extends BaseEvent, OnEvent extends BaseEvent> {
private readonly emitter = new EventEmitter();
private _dummy!: OnEvent
// ^^^^^^ dummy property added here which stores type info for `OnEvent`
emit(event: EmmitEvent): void {
this.emitter.emit(event.typ, event.payload);
}
on<Event extends EmmitEvent | OnEvent, T extends EventType<Event>>(
event: T,
listener: OnListener<EventPayloadByType<T, Event>>
): void {
this.emitter.on(event, listener);
}
}
export abstract class Controller<
EmmitEvent extends BaseEvent,
OnEvent extends BaseEvent
> extends Emitter<EmmitEvent, OnEvent> {
}
type Emmit<C extends Controller<any, any>> = C extends Controller<infer T, any> ? T : never
type On<C extends Controller<any, any>> = C extends Controller<any, infer O> ? O : never
type E = BaseEvent<"a", 1> | BaseEvent<"b", 2>
type O = BaseEvent<"c", 3> | BaseEvent<"d", 4>
class A extends Controller<E, O> {
}
type a = Emmit<A> // BaseEvent<"a", 1> | BaseEvent<"b", 2>;
type b = On<A>; // BaseEvent<"c", 3> | BaseEvent<"d", 4>
// ^^^^ correctly inferred now
declare const e: A
// type of the argument in emit is `E` ie. BaseEvent<"a", 1> | BaseEvent<"b", 2>
e.emit({typ: "a", payload: 1})
NOTE - I have changed some names in the original code注意- 我在原始代码中更改了一些名称
BaseEvent.type
to BaseEvent.typ
( type
is a keyword in TS, can cause bugs/errors) BaseEvent.type
到BaseEvent.typ
( type
是 TS 中的关键字,可能会导致错误/错误)EmmitEvents
to EmmitEvent
(it is a type for a single event) EmmitEvents
到EmmitEvent
(它是单个事件的类型)OnEvents
to OnEvent
OnEvents
到OnEvent
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.