如何实现TypeScript代码中payload的自动类型推断?
TypeScript类型推断问题:无法从EventKey自动推断payload类型
问题代码
export abstract class Scheduler<TPayload> {} export interface EventKey<T> extends Symbol {} export type SystemSpecification<TPayload> = ( args: { /** The value provided by current scheduler tick */ payload: TPayload; }, ) => void; export function defineSystem<TPayload>( system: SystemSpecification<TPayload>, scheduler: new () => Scheduler<TPayload> ) { // ... } const on = <TPayload>(eventKey: EventKey<TPayload>) => class extends Scheduler<TPayload> { // ... }; const clickEvent = Symbol('clickEvent') as EventKey<{ foo: 20 }>; defineSystem( ({ payload }) => console.log(payload.foo), on(clickEvent) );
问题描述
期望payload的类型能从clickEvent的类型({foo: number})自动推断,但实际报错:'payload' is of type unknown。
原因分析
问题出在TypeScript的类型参数推断顺序上:defineSystem的TPayload会优先从第一个参数system进行推断,但此时system中的payload没有明确类型,导致推断结果为unknown;第二个参数scheduler的类型信息未能参与到推断过程中。
解决方案
方案1:调整参数顺序引导推断
通过调换defineSystem的参数顺序,让TypeScript优先从scheduler推断TPayload,再将该类型应用到system参数:
export abstract class Scheduler<TPayload> {} export interface EventKey<T> extends Symbol {} export type SystemSpecification<TPayload> = ( args: { /** The value provided by current scheduler tick */ payload: TPayload; }, ) => void; // 调整参数顺序:先传scheduler,再传system export function defineSystem<TPayload>( scheduler: new () => Scheduler<TPayload>, system: SystemSpecification<TPayload> ) { // ... } const on = <TPayload>(eventKey: EventKey<TPayload>) => class extends Scheduler<TPayload> { // ... }; const clickEvent = Symbol('clickEvent') as EventKey<{ foo: 20 }>; defineSystem( on(clickEvent), ({ payload }) => console.log(payload.foo) // payload类型正确推断为{ foo: 20 } );
方案2:使用条件类型提取payload类型
不调整参数顺序,通过条件类型从scheduler的构造函数类型中提取TPayload:
export abstract class Scheduler<TPayload> {} export interface EventKey<T> extends Symbol {} export type SystemSpecification<TPayload> = ( args: { /** The value provided by current scheduler tick */ payload: TPayload; }, ) => void; // 定义条件类型,从Scheduler构造函数中提取TPayload type ExtractSchedulerPayload<S> = S extends new () => Scheduler<infer T> ? T : never; // 修改defineSystem,基于scheduler的类型自动提取TPayload export function defineSystem<S extends new () => Scheduler<any>>( system: SystemSpecification<ExtractSchedulerPayload<S>>, scheduler: S ) { // ... } const on = <TPayload>(eventKey: EventKey<TPayload>) => class extends Scheduler<TPayload> { // ... }; const clickEvent = Symbol('clickEvent') as EventKey<{ foo: 20 }>; defineSystem( ({ payload }) => console.log(payload.foo), // payload类型正确推断为{ foo: 20 } on(clickEvent) );
内容的提问来源于stack exchange,提问作者Charles HETIER
相关产品推荐
相关产品推荐

