TypeScript泛型函数如何正确返回对象键的对应类型?
TypeScript配置管理的类型收窄问题解决办法
你当前的代码中,SettingsProvider的get方法泛型设计导致类型推导失效——调用get<ServerSettings>('port')时,返回值类型是ServerSettings所有属性类型的联合string | number | boolean,而非预期的number。核心原因是get方法的泛型S与类内部存储的settings类型没有强关联,TypeScript无法确认传入的S就是当前实例的配置类型。
最优解决:将泛型绑定到类级别
把泛型从get方法移到SettingsProvider类上,让类的实例与具体配置类型绑定,这样get方法可以直接基于实例的配置类型推导属性类型,无需手动传入泛型:
interface Settings {} interface ServerSettings extends Settings { host: string; port: number; valid: boolean; } interface SomeOtherSettings extends Settings { enabled: boolean; } // 类级别泛型绑定具体配置类型 class SettingsProvider<S extends Settings> { constructor(private settings: S) {} // 基于类的泛型S推导key对应的类型 public get<K extends keyof S>(key: K): S[K] { return this.settings[key]; } } const settings: ServerSettings & SomeOtherSettings = { host: 'localhost', port: 8080, valid: true, enabled: false, }; const provider = new SettingsProvider(settings); const port = provider.get('port'); // 类型自动推导为number const host = provider.get('host'); // 类型自动推导为string const enabled = provider.get('enabled'); // 类型自动推导为boolean
为什么这个方案可行?
类初始化时就通过泛型S锁定了配置的具体类型,get方法的K约束为keyof S,TypeScript可以精准关联每个key对应的属性类型,完全避免了冗余的泛型参数传递。
若需保留原类结构的替代方案
如果必须让SettingsProvider类保持无泛型的设计,可以通过在get方法中添加泛型约束,让S与实例的settings类型关联,但这种写法仍需手动传入泛型,仅比双泛型略简洁:
class SettingsProvider { constructor(private settings: Settings) {} public get<S extends typeof this.settings, K extends keyof S>(key: K): S[K] { return (this.settings as S)[key]; } } // 使用时仍需传入泛型,但无需额外指定Key const port = provider.get<typeof settings>('port'); // 类型为number
不过这种写法不如类级别泛型简洁,优先推荐第一种方案。
内容的提问来源于stack exchange,提问作者c4k
相关产品推荐
相关产品推荐

