Typescript中如何限制函数参数仅接收new实例化的类对象
解决方案
TypeScript 默认采用结构化类型系统,只要类型结构匹配就会判定为兼容,所以普通类定义无法直接拦截结构一致的对象字面量。但可以通过名义类型标记的方案实现你的需求,编译层面即可禁止对象字面量传入,无需用户感知内部逻辑,也不会增加额外运行时负担。
推荐方案:类添加私有属性
TS 对类的私有属性会做名义类型校验,只有同一个类的实例才会被判定为包含该私有属性,对象字面量不可能符合要求:
declare class Foo { name: string // 仅编译时生效的私有标记,无需对外暴露,也可以不赋值无运行时开销 private readonly __nominalMarker?: void constructor(name: string) } declare function setFoo(foo: Foo): void
校验效果完全符合预期:
setFoo(new Foo("Ace")) // 正常通过编译 setFoo({ name: "Ace" }) // 编译报错:类型 "{ name: string; }" 中缺少属性 "__nominalMarker"
该方案的优势:
- 私有属性不会出现在对外的类型提示中,用户完全无感知
- 可以声明为可选且不赋值,没有任何运行时开销
- 完全拦截所有结构匹配的非实例参数,即使用户先把对象字面量赋值给变量再传入也会触发报错,可靠性拉满
备选方案:Symbol 打标
如果你不想修改类的属性定义,也可以用唯一Symbol做类型标记:
// 内部定义唯一Symbol,不对外导出 const FooNominal = Symbol('FooNominal') declare class Foo { name: string [FooNominal]: true constructor(name: string) } declare function setFoo(foo: Foo): void
由于外部无法拿到你内部定义的FooNominal这个Symbol,用户不可能手动构造出符合类型要求的对象字面量,同样可以达到拦截效果。
内容的提问来源于stack exchange,提问作者Dave
相关产品推荐
相关产品推荐

