如何正确为Vuex Method-Style Getter编写TypeScript类型定义
Vuex 方法风格 Getter TypeScript 类型报错修复
问题复现
尝试为 Vuex Method-Style getter 添加 TypeScript 类型标注时,在 getter 内部调用其他方法风格 getter 会触发 TS-2345 错误,初始实现代码如下:
interface IData { name: string; } type IGetters = { data(getters: IGetters): IData; getDataByKey: (getters: IGetters) => (name: string) => string; getName(getters: IGetters): string; } const getters: IGetters = { data(getters) { return { name: 'Hello' }; }, getDataByKey: (getters) => (name) => { return getters.data[name as keyof typeof getters.data]; }, getName(getters) { return getters.getDataByKey('name'); // 此处抛出错误 } }
报错信息:
Argument of type 'string' is not assignable to parameter of type 'IGetters'.
错误原因
类型定义没有区分 getter 编写阶段的函数签名 和 Vuex 运行后对外暴露的 getter 调用签名:
- 编写getter时,每个getter的第一个参数确实是Vuex注入的
getters对象 - 但Vuex初始化完成后,对外暴露的getter会自动绑定
getters参数,调用时不需要手动传入,方法风格getter直接传内部函数需要的参数即可
原类型把两层签名混在一起,TS就会误以为调用getDataByKey时第一个参数需要传IGetters类型的实例,导致类型校验错误。
可行解决方案
通过映射类型拆分两层签名,自动剥离getter实现时的第一个getters参数,转换为运行时的正确调用类型,修复代码如下:
interface IData { name: string; } // 定义单个getter实现时的基础类型:第一个参数为getters实例,返回值泛型自定义 type GetterImpl<G, R> = (getters: G) => R; // 工具类型:将getter实现类型转换为Vuex运行时对外暴露的调用类型 type GetterTree<G> = { [K in keyof G]: G[K] extends GetterImpl<G, infer R> ? R extends (...args: any[]) => any ? R // 方法风格getter:直接保留内部返回的函数签名 : () => R // 普通getter:转换为无入参的取值函数 : never; }; // getter实现层的类型约束 type GetterDefinitions = { data: GetterImpl<GetterDefinitions, IData>; getDataByKey: GetterImpl<GetterDefinitions, (key: keyof IData) => string>; getName: GetterImpl<GetterDefinitions, string>; }; // 对外导出的getter类型,在组件、store其他模块调用getter时使用该类型 export type IGetters = GetterTree<GetterDefinitions>; const getters: GetterDefinitions = { data() { return { name: "Hello", }; }, getDataByKey: (getters) => (key) => { // 此处key自动推导为keyof IData,不需要额外类型断言 return getters.data[key]; }, getName(getters) { // 此处调用类型校验正常,参数自动提示为keyof IData return getters.getDataByKey("name"); }, };
修复说明
- 完全符合Vuex的实际运行逻辑,不会再出现参数类型不匹配的报错
- 方法风格getter的参数、返回值类型可以完整推导,不需要加额外的
as类型断言 - 传入非法key时TS会提前抛出类型错误,类型安全性更高
内容的提问来源于stack exchange,提问作者incutonez
相关产品推荐
相关产品推荐

