You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 08:24:58