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

将JavaScript代码迁移至TypeScript时,动态为父类实例分配静态对象的类型定义生成问题

Solution to Add Instance Endpoint Properties to Type Definitions

The core issue here is that TypeScript can't infer the instance properties (like reports) added dynamically in the Api constructor from the static endpoints property. We can fix this by using generics and mapped types to explicitly link the static endpoints type to the instance's properties.

Step-by-Step Fix

1. Update the Api Class with Generics

Modify the base Api class to accept a generic parameter representing the shape of its static endpoints. We'll use a mapped type to define the instance properties that correspond to each endpoint class in endpoints:

// api.ts
class Api<Endpoints extends Record<string, typeof Endpoint>> {
  static baseUrl: string;
  static endpoints: Record<string, typeof Endpoint>;

  // Define instance properties mapped from the Endpoints generic
  [K in keyof Endpoints]: InstanceType<Endpoints[K]>;

  constructor() {
    const { baseUrl, endpoints } = this.constructor as typeof Api<Endpoints>;
    const endpointInstances = Object.entries(endpoints).reduce((instances, [name, EndpointClass]) => {
      instances[name as keyof Endpoints] = new EndpointClass(baseUrl) as InstanceType<Endpoints[keyof Endpoints]>;
      return instances;
    }, {} as { [K in keyof Endpoints]: InstanceType<Endpoints[K]> });
    
    Object.assign(this, endpointInstances);
  }
}

2. Update the Etp Subclass to Pass the Generic Parameter

When extending Api, pass the type of static endpoints to the generic parameter. This lets TypeScript infer exactly which instance properties should exist:

// etp/index.ts
import Api from '../api';
import Reports from './reports';

class Etp extends Api<{ reports: typeof Reports }> {
  static baseUrl = '/planning/api/v1/';
  static endpoints = { reports: Reports };
}

export default new Etp();

3. Verify the Generated Type Definitions

With these changes, the generated etp/index.d.ts will automatically include the reports instance property as you expected:

// etp/index.d.ts
import Api from '../api';
import Reports from './reports';
declare class Etp extends Api<{
    reports: typeof Reports;
}> {
    static baseUrl: string;
    static endpoints: {
        reports: typeof Reports;
    };
    reports: InstanceType<typeof Reports>;
}
declare const _default: Etp;
export default _default;

Why This Works

  • Generics: The Api<Endpoints> generic parameter captures the exact type of the static endpoints property for each subclass.
  • Mapped Types: [K in keyof Endpoints]: InstanceType<Endpoints[K]> tells TypeScript to create an instance property for every key in Endpoints, using the instance type of the corresponding endpoint class.
  • Type Assertions: We use type assertions in the constructor to ensure TypeScript recognizes that the dynamically created instances match the mapped type definition.

Additional Notes

  • Make sure all your endpoint classes (like Reports) extend Endpoint correctly, so InstanceType can resolve their instance types properly.
  • If you have multiple endpoint subclasses, you don't need to change the Api class further—just update the generic parameter when extending Api for each subclass (e.g., Api<{ reports: typeof Reports, users: typeof Users }>).

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 08:42:47