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

TypeScript:如何根据Action类型限制action函数的参数个数

解决TypeScript Action函数的参数约束问题

问题描述

现有以下TypeScript代码实现了动作创建函数action,但存在不符合预期的行为:

  • 调用action(TEST1)时符合预期,传入第二个参数会触发报错;
  • 调用action(TEST2)时允许不传入payload参数,而我们需要实现的是:仅当ActionTypeMaps[T]为undefined时,才允许单参数调用action,否则必须传入对应类型的payload。

原代码:

const TEST1 = "TEST1";
type TEST1 = "TEST1";

const TEST2 = "TEST2";
type TEST2 = "TEST2";

interface ActionTypeMaps {
    TEST1: undefined;
    TEST2: string;
}

export interface IAction<T extends keyof ActionTypeMaps> {
  type: T;
  payload: ActionTypeMaps[T];
}

export interface IActionWithoutPayload<T extends keyof ActionTypeMaps> {
  type: T;
  payload: undefined;
}

export function action<T extends keyof ActionTypeMaps>(
  type: T
): IActionWithoutPayload<T>;

export function action<T extends keyof ActionTypeMaps>(
  type: T,
  payload: ActionTypeMaps[T]
): IAction<T>;

export function action<T extends keyof ActionTypeMaps>(
  type: T,
  payload?: ActionTypeMaps[T]
): IActionWithoutPayload<T> | IAction<T> {
  if (payload === undefined) {
    return { type, payload: undefined }; 
  }

  return {
    payload,
    type,
  };
}

问题原因

原函数的第一个重载签名允许所有T extends keyof ActionTypeMaps类型的参数都可以单参数调用,没有对ActionTypeMaps[T]的类型做区分,导致即使ActionTypeMaps[T]是string这类非undefined类型,依然能匹配单参数重载。

解决方案

修改第一个重载的返回类型,通过条件类型约束,仅当ActionTypeMaps[T]为undefined时,该重载才生效;否则返回never,让TypeScript拒绝匹配这个重载。

修改后的代码:

const TEST1 = "TEST1";
type TEST1 = "TEST1";

const TEST2 = "TEST2";
type TEST2 = "TEST2";

interface ActionTypeMaps {
    TEST1: undefined;
    TEST2: string;
}

export interface IAction<T extends keyof ActionTypeMaps> {
  type: T;
  payload: ActionTypeMaps[T];
}

export interface IActionWithoutPayload<T extends keyof ActionTypeMaps> {
  type: T;
  payload: undefined;
}

// 仅允许ActionTypeMaps[T]为undefined的情况使用单参数调用
export function action<T extends keyof ActionTypeMaps>(
  type: T
): T extends { [K in T]: ActionTypeMaps[K] }[T] extends undefined ? IActionWithoutPayload<T> : never;

// 非undefined类型必须传入payload参数
export function action<T extends keyof ActionTypeMaps>(
  type: T,
  payload: ActionTypeMaps[T]
): IAction<T>;

export function action<T extends keyof ActionTypeMaps>(
  type: T,
  payload?: ActionTypeMaps[T]
): IActionWithoutPayload<T> | IAction<T> {
  if (payload === undefined) {
    return { type, payload: undefined }; 
  }

  return {
    payload,
    type,
  };
}

验证效果

  • action(TEST1):正常通过类型检查;
  • action(TEST1, "any"):触发类型报错,符合预期;
  • action(TEST2):触发类型报错,提示缺少payload参数;
  • action(TEST2, "test content"):正常通过类型检查。

内容的提问来源于stack exchange,提问作者albertjan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 23:50:32