You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 21:32:33