从静态上下文在TypeScript上创建新类实例时如何设置类型并避免循环类型依赖关系

从静态上下文在TypeScript上创建新类实例时如何设置类型并避免循环类型依赖关系,typescript,inheritance,constructor,typescript-typings,Typescript,Inheritance,Constructor,Typescript Typings,在解决这个问题时,我花了一天的时间尝试了各种黑客和技术,现在我要求社区分享一些知识 基本上有一个抽象模型和存储库类,它们由其他简单的具体类扩展。没什么特别的 下面提供的代码在编译时100%适用于我,但在类型方面有两个问题: 泛型中的循环类型依赖项(泛型类型“存储库”需要1个类型参数)。) 动态构造函数(类型为“typeof Model”的参数不能分配给类型为“new”(…args:unknown[])=>Model的参数)的问题你能解决这个问题吗?我在typescript和generics方面

在解决这个问题时,我花了一天的时间尝试了各种黑客和技术,现在我要求社区分享一些知识

基本上有一个抽象模型和存储库类,它们由其他简单的具体类扩展。没什么特别的

下面提供的代码在编译时100%适用于我,但在类型方面有两个问题:

  • 泛型中的循环类型依赖项(
    泛型类型“存储库”需要1个类型参数)。

  • 动态构造函数(
    类型为“typeof Model”的参数不能分配给类型为“new”(…args:unknown[])=>Model的参数)的问题你能解决这个问题吗?我在typescript和generics方面也有类似的问题。你能解决这个问题吗?我在typescript和generics方面也有类似的问题
    
    // @see https://github.com/Microsoft/TypeScript/wiki/FAQ#why-cant-i-write-typeof-t-new-t-or-instanceof-t-in-my-generic-function
    
    function create<T>(ctor: { new(...args: unknown[]): T }, ...args: unknown[]) {
      return new ctor(...args);
    }
    
    // Some real-world example, see the problematic classes below
    class Collection<T extends Model> {
      constructor(public items: T[]) {
      }
    
      all() {
        return this.items;
      }
    
      get(index: number) {
        return this.items[index];
      }
    }
    
    // Issue #1. In fact, <any> is not what I want here, but a relevant type
    abstract class Model<R extends Repository<any>> {
      exists = false;
    
      name?: string;
    
      constructor(protected repository: R, args: unknown) {
        Object.assign(this, args);
      }
    
      markExists() {
        this.exists = true;
    
        return this;
      }
    }
    
    abstract class Repository<M extends Model<any>> {
      public model = Model;
    
      public fromArray(array: unknown[]) {
        const mapped = array.map((i) => {
          // Issue #2
          const m = create(this.model, this, i);
    
          m.markExists();
    
          return m;
        }) as M[];
    
        return new Collection<M>(mapped);
      }
    
      public static fromArray<M>(array: unknown[]) {
        // Another case of issue #2
        return create(this).fromArray(array);
      }
    }
    
    class Client extends Model<Repository<any>> {
      domain = 'clients';
    }
    
    class ClientRepository extends Repository<Client> {
      domain = 'clients';
    }
    
    const array = [{ name: 'John' }, { name: 'Samantha' }];
    const hydratedClients = ClientRepository.fromArray(array);
    
    console.log(hydratedClients.get(0).name); // John
    console.log(hydratedClients.get(1).name) // Samantha