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

如何强制TypeScript函数仅接收类实例而非结构匹配的普通对象?

问题描述

下面的TypeScript代码编译时无报错,但运行时会抛出错误:

class Foo {
    foo = '';
}

class Bar {
    bar = 0;
}

function getNumber(value: Foo | Bar): number {
    if (value instanceof Bar) {
        return value.bar;
    } else {
        return value.foo.length;
    }
}

console.log(getNumber({bar: 1}));

原因是{bar: 1}只是结构匹配Bar的普通对象,并非Bar类的实例,instanceof Bar判断不成立后会进入else分支,尝试访问不存在的foo属性,导致运行时错误。

需求是:强制getNumber仅接收Foo或Bar类的实例,拒绝结构匹配的普通对象。调用getNumber({bar: 1})时,希望在编译阶段就报错,同时运行时能抛出明确提示。

解决方案

1. 编译阶段阻止结构匹配

TypeScript采用结构类型系统,默认只要属性结构匹配就会被视为兼容类型。要打破这种兼容,可给类添加私有属性或唯一Symbol属性,普通对象无法拥有这些属性,编译时就会报错。

方案一:添加私有属性

class Foo {
    private readonly _isInstance = true;
    foo = '';
}

class Bar {
    private readonly _isInstance = true;
    bar = 0;
}

function getNumber(value: Foo | Bar): number {
    if (value instanceof Bar) {
        return value.bar;
    } else {
        return value.foo.length;
    }
}

// 编译报错:类型"{ bar: number; }"缺少私有属性"_isInstance"
getNumber({bar: 1});

// 合法调用
const bar = new Bar();
bar.bar = 1;
console.log(getNumber(bar));

方案二:添加唯一Symbol属性

const instanceSymbol = Symbol('class-instance');

class Foo {
    [instanceSymbol] = true;
    foo = '';
}

class Bar {
    [instanceSymbol] = true;
    bar = 0;
}

function getNumber(value: Foo | Bar): number {
    if (value instanceof Bar) {
        return value.bar;
    } else {
        return value.foo.length;
    }
}

// 编译报错:类型"{ bar: number; }"缺少属性"[instanceSymbol]"
getNumber({bar: 1});

2. 运行时增强错误提示

保留instanceof判断的同时,添加兜底的错误抛出逻辑,确保即使绕过编译检查(比如类型断言),运行时也能给出明确提示:

function getNumber(value: Foo | Bar): number {
    if (value instanceof Bar) {
        return value.bar;
    } else if (value instanceof Foo) {
        return value.foo.length;
    } else {
        throw new Error('预期传入Foo或Bar类的实例,实际传入了普通对象');
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 14:43:18