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

如何创建仅允许必填参数的通用TypeScript函数类型?

如何创建无可选参数的通用函数工具类型?

我正在尝试实现一个工具类型,用来确保函数没有可选参数。目前针对特定函数签名的实现是有效的,但不知道怎么扩展成支持任意数量必填参数的通用类型。

当前实现

type NoOptionalArgs<F> = F extends (...args: infer P) => any
  ? undefined extends P[number]
    ? never
    : F
  : F;

// 测试结果符合预期:
type fn0 = NoOptionalArgs<() => any>;            // OK - 无参数
type fn1 = NoOptionalArgs<(x: string) => any>;   // OK - 单个必填参数
type fn2 = NoOptionalArgs<(x?: string) => any>;  // never - 包含可选参数

但当我尝试创建通用类型时出现问题:

type fnType = NoOptionalArgs<(...args: any[]) => any>;  // 结果为never

需求

我想要的fnType需要满足:

  • 允许包含任意数量的必填参数
  • 禁止包含任何可选参数
  • 支持任意参数类型

示例

const good: fnType = (x: string) => 'x';  // 合法,无报错
const bad: fnType = (x?: string) => 'x';  // 应当报错

这是否可行?


其他无效尝试

尝试1

type RequiredArray<T> = T extends any[] 
  ? undefined extends T[number] 
    ? never 
    : T
  : never;

type fnType = <T extends any[]>(...args: T extends RequiredArray<T> ? T : never) => any;

尝试2

type fnType = <T extends readonly any[]>(
  ...args: { [K in keyof T]: Exclude<T[K], undefined> }
) => any;

解决方案

要实现这个需求,我们可以利用TypeScript对函数参数元组的结构推断,通过约束参数元组中不存在可选标记来达成目标。

基础实现版本

type NoOptionalParams<F> = 
  F extends (...args: infer P) => infer R 
    ? P extends [...{ [K in keyof P]: Exclude<P[K], undefined> }]
      ? F
      : never
    : never;

// 通用函数类型定义
type fnType = NoOptionalParams<(...args: any[]) => any>;

验证效果

const good1: fnType = () => 'ok'; // 合法
const good2: fnType = (a: number, b: string) => true; // 合法
const bad1: fnType = (x?: string) => 'x'; // 报错:类型不匹配
// 注意:必填的可空参数(如string | undefined)不属于可选参数,会被允许
const validNullable: fnType = (x: string | undefined) => 'x'; // 合法

原理说明

  • 通过infer P推断函数的参数元组P
  • 检查原元组P是否等于「将每个成员排除undefined后的元组」:如果原元组包含可选参数,排除undefined后的元组会丢失可选标记,结构与原元组不一致,因此条件不成立,返回never
  • 对于(...args: any[]) => any这个通用签名,该约束会自动过滤掉所有带可选参数的函数,仅保留参数全为必填的函数

严格区分可选参数与必填可空参数的版本

如果需要严格拒绝可选参数,但允许必填的可空参数(即区分x?: string和x: string | undefined),可以利用元组的可选标记特性实现:

type IsAllRequired<T extends any[]> = 
  T extends [...infer U, infer Last] 
    ? IsAllRequired<U> & (Last extends undefined ? never : unknown)
    : unknown;

type NoOptionalParamsStrict<F> = 
  F extends (...args: infer P) => infer R 
    ? IsAllRequired<P> extends unknown
      ? F
      : never
    : never;

type fnTypeStrict = NoOptionalParamsStrict<(...args: any[]) => any>;

验证效果

const validNullable: fnTypeStrict = (x: string | undefined) => 'x'; // 合法
const invalidOptional: fnTypeStrict = (x?: string) => 'x'; // 报错:类型不匹配

内容的提问来源于stack exchange,提问作者Anon A. Mouse

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 20:04:53