TypeScript如何通过类映射获取实例类型而非构造函数类型?
解决TypeScript中从类映射获取实例类型的问题
问题分析
你当前的ClassMap类型存储的是类的构造函数类型(typeof Foo、typeof Bar),而不是类的实例类型(Foo、Bar),所以直接访问val属性会报错——因为构造函数本身没有val属性,val是实例的属性。
解决方案
TypeScript提供了内置工具类型InstanceType,可以从构造函数类型中提取对应的实例类型。下面提供两种常用的处理方式:
方式1:直接针对单个类型转换
如果只需要获取某一个键对应的实例类型,可以直接用InstanceType包裹构造函数类型:
class Foo { constructor(public val: number) {} } class Bar { constructor(public val: string) {} } const classMap = { foo: Foo, bar: Bar, } as const; type ClassMap = typeof classMap; // 直接转换为实例类型 type InferredFoo = InstanceType<ClassMap["foo"]>; // Foo type ShouldBeNumber = InferredFoo["val"]; // number,无报错
方式2:创建完整的实例类型映射
如果需要把整个ClassMap转换成实例类型的映射,可以自定义一个映射类型,结合InstanceType和条件类型处理(支持混合非类属性的场景):
class Foo { constructor(public val: number) {} } class Bar { constructor(public val: string) {} } const classMap = { foo: Foo, bar: Bar, baz: 10, } as const; type ClassMap = typeof classMap; // 自定义映射类型:将构造函数类型转为实例类型,非构造函数类型保持原样 type InstanceMap<T> = { [K in keyof T]: T[K] extends new (...args: any[]) => infer R ? R : T[K] }; type ClassInstanceMap = InstanceMap<ClassMap>; // { readonly foo: Foo, readonly bar: Bar, readonly baz: 10 } type InferredFoo = ClassInstanceMap["foo"]; // Foo type ShouldBeNumber = InferredFoo["val"]; // number type BazType = ClassInstanceMap["baz"]; // 10
说明
InstanceType<ConstructorType>是TypeScript内置工具类型,专门用于从构造函数类型中提取实例类型,完全是编译时操作,不会影响运行时代码。- 自定义的
InstanceMap类型通过条件类型判断属性是否为构造函数,兼容混合了类和其他类型值的映射场景,保持非类属性的类型不变。
内容的提问来源于stack exchange,提问作者Adam B.
相关产品推荐
相关产品推荐

