如何让Typescript ConfigService类根据配置ID动态返回对应泛型类型?
解决TypeScript中ConfigService动态返回配置的类型识别问题
问题背景
需要实现一个ConfigService类,根据构造函数传入的配置ID动态返回对应类型的配置,但调用get()方法后,TypeScript无法正确识别具体配置类型,报错“Property 'propA' does not exist on type 'Configs'”。
原代码
export type ConfigA = { id: "configA"; name: string; propA: string; }; export type ConfigB = { id: "configB"; name: string; propB: string; }; export type Configs = ConfigA | ConfigB; export class ConfigService<C extends Configs> { private readonly configCollection: CollectionReference<C>; constructor(private configName: C["id"]) { this.configCollection = db.collection("config") as CollectionReference<C>; } public async get() { const configSnap = await this.configCollection.doc(this.configName).get(); return configSnap.data(); } }
调用代码
const configA = await new ConfigService("configA").get(); const propA = configA.propA;
报错信息
Property 'propA' does not exist on type 'Configs'. Property 'propA' does not exist on type 'ConfigB'
解决方案
核心问题是原泛型约束未建立配置ID与具体配置类型的精准关联,TypeScript无法从传入的ID推导出对应的具体类型。通过以下调整解决:
调整后的代码
export type ConfigA = { id: "configA"; name: string; propA: string; }; export type ConfigB = { id: "configB"; name: string; propB: string; }; // 建立配置ID到具体类型的映射 export type ConfigMap = { configA: ConfigA; configB: ConfigB; }; // 保留原Configs类型(可选,用于需要泛指所有配置的场景) export type Configs = ConfigMap[keyof ConfigMap]; export class ConfigService<K extends keyof ConfigMap> { private readonly configCollection: CollectionReference<ConfigMap[K]>; constructor(private configName: K) { this.configCollection = db.collection("config") as CollectionReference<ConfigMap[K]>; } public async get(): Promise<ConfigMap[K] | undefined> { const configSnap = await this.configCollection.doc(this.configName).get(); return configSnap.data(); } }
调用示例
const configA = await new ConfigService("configA").get(); if (configA) { const propA = configA.propA; // TypeScript可正确识别类型,无报错 } const configB = await new ConfigService("configB").get(); if (configB) { const propB = configB.propB; // 同样支持ConfigB的类型识别 }
调整说明
- 新增ConfigMap映射:将每个配置ID与对应的具体类型绑定,让TypeScript能通过ID精准定位到目标类型,避免联合类型的模糊性。
- 泛型参数调整:将
ConfigService的泛型改为K extends keyof ConfigMap,构造函数传入的configName会被约束为映射的键,TypeScript据此自动推导返回的具体配置类型。 - 明确返回类型:
get()方法返回ConfigMap[K] | undefined(适配Firestore的data()可能返回undefined的情况),确保调用后类型清晰。
内容的提问来源于stack exchange,提问作者Jeremy Walters
相关产品推荐
相关产品推荐

