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

如何在TypeScript编译时确保函数参数值的唯一性?

实现函数调用时重复标识符触发类型错误

要实现同一标识符重复传入函数时触发TypeScript类型错误,核心是利用泛型累积已使用的标识符集合,让函数每次调用后更新自身的类型约束,限制后续调用只能传入未使用过的ID。

方案1:链式调用的函数实现

先定义允许的标识符列表,再通过泛型函数追踪已使用的ID:

// 定义所有允许使用的标识符
type AllIds = 'id-1' | 'id-2';

// 定义泛型函数类型,UsedIds记录已使用的ID,默认是空集合
type UniqueFoo<UsedIds extends AllIds = never> = {
  (id: Exclude<AllIds, UsedIds>): UniqueFoo<UsedIds | typeof id>;
};

// 实现函数,每次调用后返回更新泛型约束的自身
const foo: UniqueFoo = (id) => {
  console.log(`my id: ${id}`);
  return foo as UniqueFoo<typeof id>;
};

// 使用示例
const fooAfterFirstCall = foo('id-1'); // 正常执行,返回的函数已排除'id-1'
fooAfterFirstCall('id-1'); // ❌ 类型错误:'id-1'已被使用
fooAfterFirstCall('id-2'); // ✅ 正常执行
fooAfterFirstCall('id-2'); // ❌ 类型错误:'id-2'已被使用

方案2:类封装实现

如果更倾向于类的写法,可以用类的泛型参数记录已使用的ID:

type AllIds = 'id-1' | 'id-2';

class UniqueFoo<UsedIds extends AllIds = never> {
  call(id: Exclude<AllIds, UsedIds>): UniqueFoo<UsedIds | typeof id> {
    console.log(`my id: ${id}`);
    // 类型断言更新泛型参数
    return this as unknown as UniqueFoo<UsedIds | typeof id>;
  }
}

// 使用示例
const foo = new UniqueFoo();
const foo1 = foo.call('id-1'); // 正常调用,返回的实例已排除'id-1'
foo1.call('id-1'); // ❌ 类型错误
foo1.call('id-2'); // ✅ 正常调用

原理说明

  • 泛型参数UsedIds会累积每次调用传入的标识符,初始值为never(空集合)。
  • Exclude<AllIds, UsedIds>确保函数参数只能是未被使用过的标识符。
  • 每次调用后返回的函数/实例,其泛型参数会更新为UsedIds | typeof id,相当于把当前ID加入已使用集合,后续调用就无法再传入该ID。

需要注意:TypeScript是静态类型系统,同一个变量的类型不会在运行时动态更新,所以必须通过赋值新变量来获取更新后的类型约束,才能触发重复调用的类型错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 05:55:18