如何为TypeScript非类对象实现链式函数调用(Vue3+Pinia场景)
问题描述
我有一段基于Vue3(Composition API)的Pinia store代码,但本质是TypeScript问题。代码如下:
export const useCommonStore = defineStore("commmon", () => { const commonState = reactive({ isRequestLoading: false, lookupsLoaded: false, lineOfBusinesses: LookupItem[] // 此处写法有误,正确应为 lineOfBusinesses: [] as LookupItem[] }); const emptyOption = { value: 0, name: "No selection" }; const withEmptyOption = (options: Array<ILookupItem>) => { return [emptyOption, ...options]; }; });
目前在Vue组件中是这样调用的:
commonStore.withEmptyOption(commonStore.commonState.lineOfBusinesses)
但我希望改成更简洁的链式调用写法:
commonStore.commonState.lineOfBusinesses.withEmptyOption()
不知道该如何实现。
解决方案
方法一:扩展Array原型(全局可用,注意原型污染风险)
先在TypeScript类型声明文件(比如types/array.d.ts)中添加扩展定义,避免类型报错:
interface Array<T> { withEmptyOption(): Array<T & { value: number; name: string }>; }
然后在Pinia store中实现这个方法,确保能访问到emptyOption:
export const useCommonStore = defineStore("commmon", () => { const commonState = reactive({ isRequestLoading: false, lookupsLoaded: false, lineOfBusinesses: [] as LookupItem[] }); const emptyOption = { value: 0, name: "No selection" }; // 给Array原型添加方法,仅在不存在时添加避免重复定义 if (!Array.prototype.withEmptyOption) { Array.prototype.withEmptyOption = function() { return [emptyOption, ...this]; }; } // 原方法可按需保留或删除 const withEmptyOption = (options: Array<ILookupItem>) => { return [emptyOption, ...options]; }; return { commonState, withEmptyOption }; });
完成后就能直接使用commonStore.commonState.lineOfBusinesses.withEmptyOption()了。
方法二:自定义数组类(更安全,避免原型污染)
创建一个继承自Array的自定义类,内置withEmptyOption方法:
class LookupArray<T extends ILookupItem> extends Array<T> { private emptyOption = { value: 0, name: "No selection" }; withEmptyOption() { return [this.emptyOption, ...this]; } }
然后在Pinia store中初始化lineOfBusinesses为该类的实例:
export const useCommonStore = defineStore("commmon", () => { const commonState = reactive({ isRequestLoading: false, lookupsLoaded: false, // 用自定义数组类初始化 lineOfBusinesses: new LookupArray<ILookupItem>() }); // 原方法可按需保留 const withEmptyOption = (options: Array<ILookupItem>) => { return [commonState.lineOfBusinesses.emptyOption, ...options]; }; return { commonState, withEmptyOption }; });
这种方式不会污染全局Array原型,同时能实现链式调用。注意后续更新lineOfBusinesses时,要确保赋值的是LookupArray实例,比如请求数据后可以用new LookupArray(...responseData)包裹返回值。
额外修正
原代码中lineOfBusinesses: LookupItem[]的写法不符合TypeScript语法,必须改成lineOfBusinesses: [] as LookupItem[]或者用自定义类实例初始化,否则会触发类型错误。
内容的提问来源于stack exchange,提问作者Redeemed1
相关产品推荐
相关产品推荐

