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

如何定义TypeScript函数:接受A/B实例集合但拒绝A|B联合类型参数?

TypeScript 函数参数类型约束实现

需求:编写单个TypeScript函数,满足以下要求:

  • 支持传入任意数量的A类或B类实例(A与B相互独立,无继承关系)
  • 禁止传入类型为A|B的联合类型变量作为参数(包括单个或多个联合类型变量)
  • 必须使用单个函数实现,不能拆分为多个函数

初始示例代码:

class A {/* 省略具体实现 */}
class B {/* 省略具体实现 */}

let a:A = new A();
fn(a); // 明确类型调用,允许通过编译

let b:B = new B();
fn(b); // 明确类型调用,允许通过编译

let c:A|B = someCondition ? new A() : new B();
fn(c); // 联合类型变量调用,需触发TypeScript编译错误

补充说明:实际需要支持可变数量的参数,示例如下:

class A {/* 省略具体实现 */}
class B {/* 省略具体实现 */}

let a:A = new A();
let b:B = new B();
let c:A|B = someCondition ? new A() : new B();

interface Fn {
    (...args: V[]) => void;
}

const fn: Fn = (...args) => {/* 省略函数实现 */};

fn(a); // 单个明确类型参数,允许
fn(b); // 单个明确类型参数,允许
fn(a, b, a, b); // 多个混合明确类型参数,允许
fn(c); // 联合类型变量参数,需触发编译错误

解决方案

通过自定义类型约束,区分明确的A/B类型和A|B联合类型,实现需求:

class A {/* 省略具体实现 */}
class B {/* 省略具体实现 */}

// 判断类型是否为联合类型
type IsUnion<T> = [T] extends [infer U] ? U extends T ? T extends U ? false : true : false : false;

// 仅允许非联合类型的A或B
type AllowedArg<T> = IsUnion<T> extends false ? (T extends A | B ? T : never) : never;

// 对参数数组的每个元素应用AllowedArg约束
type AllowedArgs<T extends any[]> = {
    [K in keyof T]: AllowedArg<T[K]>;
};

// 定义符合要求的函数
const fn = <T extends any[]>(...args: AllowedArgs<T>) => {
    // 在这里编写函数逻辑
    console.log(args);
};

// 测试用例
let a:A = new A();
fn(a); // ✅ 编译通过

let b:B = new B();
fn(b); // ✅ 编译通过

fn(a, b, a, b); // ✅ 编译通过

let c:A|B = Math.random() > 0.5 ? new A() : new B();
fn(c); // ❌ 编译错误:类型'A | B'不能赋值给类型'never'

fn(c, c); // ❌ 编译错误:类型'A | B'不能赋值给类型'never'

原理说明

  1. IsUnion<T>:通过条件类型判断传入的类型是否为联合类型。如果T是联合类型,返回true,否则返回false。
  2. AllowedArg<T>:仅允许非联合类型的A或B,如果T是联合类型则返回never,从而触发编译错误。
  3. AllowedArgs<T>:遍历参数数组的每个元素,对每个元素应用AllowedArg约束,确保所有参数都是明确的A或B实例,而非联合类型变量。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 20:25:47