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

如何在TypeScript中实现互不兼容的不透明类型约束?

问题

此问题与其他类型定义问题无关。

请观察以下代码:

interface Machine<OpaqueType> {
    get(): OpaqueType,
    update(t: OpaqueType);
}

const f = <U, V>(uMachine: Machine<U>, vMachine: Machine<V>) => {
    const u = uMachine.get();
    vMachine.update(u);
}

这段代码最后一行无法编译,报错信息:

Argument of type 'U' is not assignable to parameter of type 'V'. 'V' could be instantiated with an arbitrary type which could be unrelated to 'U'.

这正是预期效果:两台机器各自处理自身类型的数据,未经刻意协调无法互相操作。

但泛型<U, V>的写法略显冗余,因为函数并不关心具体类型。希望写成如下形式,且让这段代码无法编译(因为两个unknown对应的实际类型不一定兼容):

const f = (uMachine: Machine<unknown>, vMachine: Machine<unknown>) => {
    const u = uMachine.get();
    vMachine.update(u);
}

补充说明:第二段代码本就不应通过编译,这是错误写法,希望编译器能捕获该错误。

请问在TypeScript中能否实现这种需求?


解决方案

可以实现,核心是通过泛型关联两个Machine实例的实际类型,避免用unknown抹除类型信息,同时让编译器能检测类型兼容性。

方法一:用单一泛型约束两个Machine的类型一致性

让函数声明一个泛型参数,要求传入的两个Machine必须属于同一类型,这样既不用显式写<U, V>,又能保证类型不匹配时报错:

interface Machine<OpaqueType> {
    get(): OpaqueType;
    update(t: OpaqueType): void;
}

// 泛型T约束两个Machine的类型必须一致
const f = <T>(uMachine: Machine<T>, vMachine: Machine<T>) => {
    const u = uMachine.get();
    vMachine.update(u); // 类型匹配,编译通过
}

// 测试:传入不同类型的Machine会触发报错
const numMachine: Machine<number> = { get: () => 1, update: () => {} };
const strMachine: Machine<string> = { get: () => "a", update: () => {} };
f(numMachine, strMachine); // 报错:类型不兼容,符合预期

方法二:用辅助类型隐式检查类型兼容性

如果需要保留“参数看起来是Machine<unknown>”的形式,可以通过辅助类型在编译期检查两个Machine的实际类型是否兼容:

interface Machine<OpaqueType> {
    get(): OpaqueType;
    update(t: OpaqueType): void;
}

// 辅助类型:若U不能赋值给V,则返回never触发报错
type AssertAssignable<U, V> = U extends V ? unknown : never;

// 泛型自动推导,无需显式声明U、V
const f = <U, V>(
    uMachine: Machine<U>,
    vMachine: Machine<V> & AssertAssignable<U, V>
) => {
    const u = uMachine.get();
    vMachine.update(u);
}

// 测试:不同类型的Machine传入会报错
f(numMachine, strMachine); // 编译报错,符合需求

为什么直接用Machine<unknown>不行?

unknown是顶级类型,任何类型都能赋值给它,且unknown值可以赋值给unknown。当参数声明为Machine<unknown>时,u的类型是unknown,vMachine.update接受的也是unknown,编译器会认为类型兼容,因此不会报错。要实现需求,必须通过泛型追踪两个Machine的实际类型,而非用unknown抹除类型信息。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 20:49:55