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

如何用TypeScript为基于对象描述生成类的generator函数添加类型定义?

如何为基于对象描述生成类的函数编写TypeScript类型定义?

问题场景

现有一个generator函数,接收对象形式的类原型描述,转换后返回对应的类。但当前TypeScript无法正确推断生成类的实例与静态成员类型,导致使用时出现类型报错。需要为该函数编写合适的类型定义,实现完整的类型校验。

代码示例

function generator(prototype) {
  const cls = class { };

  if (prototype.$name) {
    cls.name = prototype.$name;
  }

  // 原型转换逻辑(省略具体实现)
  cls.prototype = prototype;

  return cls;
}

const MyClass = generator({
  f1: '2',
  _f2: { $default: '' },
  f2: {
    get() { return this._f2; }, // this 被推断为 any
    set(v) { this._f2 = v; }
  },
  f3: {
    $type: String,
    $default: 'asd',
    get() { return this.f1 + this.f2; },
    set(v) { this.f1 = v[0]; this.f2 = v[1]; }
  },
  m() { return this.f3; },
  $static: {
    s1: 'static',
    s2: { $def: 'static 2' },
    s3: { get() { return 'static 3'; } }
  }
});

// 以下均会触发类型报错:属性不存在于类型 typeof cls/cls
console.log(MyClass.s1);
console.log(MyClass.s2);
console.log(MyClass.s3);
const o = new MyClass();
console.log(o.f1);
console.log(o.f2);
console.log(o.f3);
console.log(o.m());

解决方案

通过高级泛型+条件类型解析输入的原型描述,建立输入与输出类之间的类型映射关系,让TypeScript正确推断实例和静态成员类型。

1. 定义原型描述的基础类型

先明确输入对象中各类成员的结构类型:

// 属性描述类型:支持直接值、带默认值/类型的配置、访问器
type PropertyDescriptor<T = any> = 
  | T
  | { $default?: T; $type?: new () => T }
  | { get(): T; set?(v: T): void };

// 方法类型:约束this指向实例
type InstanceMethod<TInstance> = (this: TInstance, ...args: any[]) => any;

// 静态成员描述类型
type StaticDescriptor<T = any> = 
  | T
  | { $def?: T }
  | { get(): T };

// 完整的原型输入类型
type PrototypeInput<TInstance, TStatic> = {
  $name?: string;
  $static?: { [K in keyof TStatic]: StaticDescriptor<TStatic[K]> };
} & {
  [K in keyof TInstance]: 
    TInstance[K] extends Function ? InstanceMethod<TInstance> : PropertyDescriptor<TInstance[K]>;
};

2. 编写类型转换工具

创建工具类型,将输入的描述转换为实际的实例/静态类型:

// 从属性描述中提取实际类型
type ExtractPropertyType<D> = 
  D extends { get(): infer T } ? T :
  D extends { $default: infer T } ? T :
  D extends { $type: new () => infer T } ? T :
  D extends any ? D : never;

// 从静态描述中提取实际类型
type ExtractStaticType<D> = 
  D extends { get(): infer T } ? T :
  D extends { $def: infer T } ? T :
  D extends any ? D : never;

// 转换原型输入为实例类型
type InstanceTypeFromInput<Input> = {
  [K in keyof Input as Exclude<K, '$name' | '$static'>]: 
    Input[K] extends InstanceMethod<any> ? Input[K] : ExtractPropertyType<Input[K]>;
};

// 转换静态输入为静态类型
type StaticTypeFromInput<Input> = 
  Input extends { $static: infer S } ? {
    [K in keyof S]: ExtractStaticType<S[K]>;
  } : {};

3. 为generator函数添加泛型注解

组合上述工具类型,为函数定义完整的类型约束:

function generator<
  TInput extends PrototypeInput<TInstance, TStatic>,
  TInstance = InstanceTypeFromInput<TInput>,
  TStatic = StaticTypeFromInput<TInput>
>(prototype: TInput): (new () => TInstance) & TStatic {
  const cls = class { } as any;

  if (prototype.$name) {
    cls.name = prototype.$name;
  }

  // 保留你的原型转换逻辑
  cls.prototype = prototype;

  // 处理静态成员挂载
  if (prototype.$static) {
    Object.assign(cls, prototype.$static);
  }

  return cls;
}

4. 验证效果

此时使用generator生成类时,TypeScript会自动推断所有成员的类型,不再出现报错:

const MyClass = generator({
  f1: '2',
  _f2: { $default: '' },
  f2: {
    get() { return this._f2; },
    set(v) { this._f2 = v; }
  },
  f3: {
    $type: String,
    $default: 'asd',
    get() { return this.f1 + this.f2; },
    set(v) { this.f1 = v[0]; this.f2 = v[1]; }
  },
  m() { return this.f3; },
  $static: {
    s1: 'static',
    s2: { $def: 'static 2' },
    s3: { get() { return 'static 3'; } }
  }
});

// 静态成员类型正确识别
console.log(MyClass.s1); // 类型:string
console.log(MyClass.s2); // 类型:string
console.log(MyClass.s3); // 类型:string

const o = new MyClass();
// 实例成员类型正确识别
console.log(o.f1); // 类型:string
console.log(o.f2); // 类型:string
console.log(o.f3); // 类型:string
console.log(o.m()); // 类型:string

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 20:17:26