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

TypeScript中如何将通过MyClass.defaults设置的必填构造参数设为可选

实现方案
interface BaseOptions {
  version: string;
  [key: string]: unknown;
}

// 工具类型:无剩余必填属性时构造函数参数自动变为可选
type OptionalIfEmpty<T> = {} extends T 
  ? (options?: Partial<T>) => void 
  : (options: Partial<T>) => void;

type BaseConstructor<TOptions extends BaseOptions = BaseOptions> = 
  & (new (...args: ConstructorParameters<OptionalIfEmpty<Omit<TOptions, keyof BaseOptions>>> & [options?: Partial<TOptions>]) => Base<TOptions>)
  & {
    defaults<TDefaults extends Partial<TOptions>>(
      defaults: TDefaults
    ): BaseConstructor<Omit<TOptions, keyof TDefaults> & TDefaults>;
  };

class Base<TOptions extends BaseOptions = BaseOptions> {
  static defaults<TDefaults extends Partial<BaseOptions>>(
    this: BaseConstructor,
    defaults: TDefaults
  ): BaseConstructor<Omit<BaseOptions, keyof TDefaults> & TDefaults> {
    return class extends (this as any) {
      constructor(...args: any[]) {
        super(Object.assign({}, defaults, args[0] || {}));
      }
    } as any;
  }

  constructor(options: TOptions) {
    this.options = options;
  }
  
  options: TOptions;
}

效果验证

所有需求场景均可正常通过类型校验:

// 原始Base构造必须传version
const test = new Base({
  version: "1.2.3"
})

// defaults方法入参version可选
const MyBaseWithDefaults = Base.defaults({
  foo: "bar"
})
const test2 = new MyBaseWithDefaults({ version: "2.0.0" })

// defaults传version后新构造无需传version
const MyBaseWithVersion = Base.defaults({
  version: "1.2.3",
  foo: "bar"
})
const testWithDefaults = new MyBaseWithVersion()
// 以下两个属性均被自动推导为string类型
testWithDefaults.options.version
testWithDefaults.options.foo

// 支持级联defaults调用
const CascadedBase = Base.defaults({ one: "1" }).defaults({ two: "2" }).defaults({ version: "3.0.0" })
const cascadedTest = new CascadedBase()
cascadedTest.options.one // string
cascadedTest.options.two // string
cascadedTest.options.version // string

核心逻辑说明

  • 用BaseConstructor类型统一封装构造函数签名和defaults方法签名,保证级联调用时泛型类型正确传递
  • 通过工具类型OptionalIfEmpty判断当前剩余必填属性是否为空,为空时构造函数参数自动变为可选
  • 每次调用defaults都会合并传入的默认值到泛型参数中,自动过滤已经设置默认值的必填属性

内容的提问来源于stack exchange,提问作者Gregor

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.13 18:06:01