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

如何在TypeScript中编写支持方法扩展功能的构造函数

解决思路:利用 TypeScript 模块增强(Module Augmentation)实现可扩展的类型定义

你的核心问题是原来的Methods接口用了泛化的字符串索引签名,丢失了具体方法的类型信息。我们可以把Methods接口作为扩展点,让用户在新增方法时通过模块增强补充类型定义,TS 会自动合并接口声明,让实例获得完整的类型提示。

第一步:改造基础模块代码

methods.ts

删除泛化的索引签名,定义空接口作为扩展锚点,同时给addMethod添加类型约束:

export interface Methods {}

const methods: Methods = {} as Methods;

export default function getMethods(): Methods {
  return { ...methods };
}

// 约束传入的方法名和方法类型必须和Methods接口定义匹配
export function addMethod<Name extends keyof Methods>(
  methodName: Name,
  method: Methods[Name]
) {
  methods[methodName] = method;
}
programmer.ts

只需要调整getInstructionsFrom里的类型断言,替换掉@ts-expect-error即可,其余代码可以保留:

import type { Methods } from "./methods";
import getMethods from "./methods";

export type I_Programmer = Methods & {
  addInstruction: (arg: { cmd: string; args: unknown[] }) => void;
};

interface ProgrammerConstructor {
  new (): I_Programmer;
  (): void;
}

const retriveInstructionsMethod = "SECRET_METHOD_NAME";
const secretKey = "ACCESS_KEY";

const Programmer = function (this: I_Programmer) {
  const instructions: object[] = [];
  this.addInstruction = (value) => instructions.push(value);

  Object.defineProperty(this, retriveInstructionsMethod, {
    enumerable: false,
    writable: false,
    value(key: string) {
      if (key === secretKey) return instructions;
    },
  });

  const methods = getMethods();
  for (const key of Object.keys(methods))
    this[key] = (...args: unknown[]) => methods[key].apply(this, args);
} as ProgrammerConstructor;

// 用类型断言代替@ts-expect-error,类型更安全
export function getInstructionsFrom(programmer: I_Programmer): object[] {
  return (programmer as any)[retriveInstructionsMethod](secretKey);
}

export default Programmer;

第二步:用户扩展时的类型声明

用户新增方法时,只需要先通过模块增强扩展Methods接口,再编写对应方法即可,类型会自动同步到Programmer实例上:

testUsages.ts
import { addMethod } from "./methods";
import type { I_Programmer } from "./programmer";
import Programmer, { getInstructionsFrom } from "./programmer";

// 模块增强:扩展Methods接口,新增方法的类型定义
declare module "./methods" {
  interface Methods {
    code: (this: I_Programmer, task: string, deadline: string) => this;
    cry: (this: I_Programmer, words: string) => this;
    // 后续新增方法直接在这里补类型定义即可
  }
}

// 编写方法时TS会自动校验this类型和参数、返回值类型
function code(this: I_Programmer, task: string, deadline: string) {
  this.addInstruction({ cmd: "code", args: [task, deadline] });
  return this;
}

function cry(this: I_Programmer, words: string) {
  this.addInstruction({ cmd: "cry", args: [words] });
  return this;
}

// addMethod会自动校验方法名和方法类型是否匹配接口定义
addMethod("code", code);
addMethod("cry", cry);

// 实例上已经有完整的code、cry方法类型提示,参数错误会直接报错
const desperateProgrammer = new Programmer()
  .code("用TypeScript写一个库", "10天")
  .cry("天呐为什么一切都这么复杂,求求大佬帮忙!");

console.log(getInstructionsFrom(desperateProgrammer));

方案优势

  • 完全类型安全:方法名、参数、返回值都有严格校验,不会出现类型丢失的问题
  • 扩展成本极低:新增方法只需要加一行接口定义+调用addMethod,不需要继承基类或者修改原模块代码
  • 内部逻辑隔离:addInstruction和隐藏的指令提取方法不会暴露给终端用户,符合你的安全需求

内容的提问来源于stack exchange,提问作者h-sifat

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 16:36:03