如何在TypeScript中将类型映射到对象实例类型?
解决方案
要实现根据实例类型约束第二个参数的类型,核心是让TypeScript能够准确区分不同的类实例类型,结合类型映射来关联实例与目标类型。以下是两种可行方案:
方案一:添加唯一标识属性(Tag)
由于TypeScript是结构类型系统,仅靠方法返回值无法区分结构相似的类。我们可以给每个子类添加一个只读的唯一标识属性,让TypeScript能识别它们的差异:
class Buzz{ name: string constructor(name: string) { this.name = name; } greet() { console.log(`Hi, I'm ${this.name}`) } getTitle():string { return `Senior commander ${this.name}` } } class Foo extends Buzz{ readonly type = 'Foo' as const; // 添加唯一标识 constructor(name: string) { super(name); } getTitle():string { return `Professor ${this.name} the Fourth` } } class Bar extends Buzz{ readonly type = 'Bar' as const; // 添加唯一标识 constructor(name: string) { super(name); } getTitle():string { return `${this.name} the one and only.` } } // 定义实例类型到目标值的映射 type InstanceToValue = { Foo: 'Foo'; Bar: 'Bar'; } // 利用标识属性做类型约束 function fooBarObj<T extends Foo | Bar>(s: T, t: InstanceToValue[T['type']]){}; // 验证调用 fooBarObj(new Foo('foo'), 'Foo') // ✅ 正确 fooBarObj(new Bar('bar'), 'Bar') // ✅ 正确 fooBarObj(new Foo('foo'), 'Bar') // ❌ 类型错误
方案二:利用构造函数类型映射
不需要修改类结构,直接通过实例的构造函数类型来做映射:
class Buzz{ name: string constructor(name: string) { this.name = name; } greet() { console.log(`Hi, I'm ${this.name}`) } getTitle():string { return `Senior commander ${this.name}` } } class Foo extends Buzz{ constructor(name: string) { super(name); } getTitle():string { return `Professor ${this.name} the Fourth` } } class Bar extends Buzz{ constructor(name: string) { super(name); } getTitle():string { return `${this.name} the one and only.` } } // 定义构造函数到目标值的映射 type ConstructorToValue = { [K in typeof Foo]: 'Foo'; [K in typeof Bar]: 'Bar'; } // 通过实例的构造函数类型约束参数 function fooBarObj<T extends Foo | Bar>(s: T, t: ConstructorToValue[typeof s]){}; // 验证调用 fooBarObj(new Foo('foo'), 'Foo') // ✅ 正确 fooBarObj(new Bar('bar'), 'Bar') // ✅ 正确 fooBarObj(new Bar('bar'), 'Foo') // ❌ 类型错误
原理说明
- 方案一通过添加
readonly type属性,给每个子类实例赋予了唯一的字面量类型,让TypeScript能精准区分不同实例类型,再通过索引访问映射类型得到对应的约束值。 - 方案二利用
typeof 实例会返回其构造函数类型的特性,通过构造函数类型与目标值的映射,实现参数类型的关联约束。
内容的提问来源于stack exchange,提问作者Khaled
相关产品推荐
相关产品推荐

