Typescript 从ConstructorParameters获取第n个参数类型

Typescript 从ConstructorParameters获取第n个参数类型,typescript,generics,typescript-generics,Typescript,Generics,Typescript Generics,我尝试使用ConstructorParameters类型获取类构造函数的第一个参数类型,作为接口的扩展,可能更好地显示代码: // base.ts --------------------------------------------------------------------- interface IConfig { someProperty: string; } export class Base { constructor(config: IConfig) { } }

我尝试使用ConstructorParameters类型获取类构造函数的第一个参数类型,作为接口的扩展,可能更好地显示代码:

// base.ts ---------------------------------------------------------------------
interface IConfig {
  someProperty: string;
}

export class Base {
  constructor(config: IConfig) {
  }
}

// derived.ts ------------------------------------------------------------------
interface IConfig extends ConstructorParameters<typeof Base> {
                                                         // ^ tried [0] here but 
                                                         // that doesn't work
}

export class Derived extends Base {
  constructor(config: IConfig) {
    super(config); // this doesn't work because ConstructorParameters returns
                   // a type tuple which is then placed on IConfig for this
                   // class.  I want to pick the type of the first argument
                   // and I can't figure out how to select just the first
                   // arguments type (i.e. [0] but that doesn't work).
  }
}

有没有人知道如何使用ConstructorParameters类型,或者知道一些我不知道的东西?

刚刚想出来,但可以接受其他建议:

// derived.ts ------------------------------------------------------------------
type BaseConfigType = ConstructorParameters<typeof Base>[0];
interface IConfig extends BaseConfigType {

}

export class Derived extends Base {
  constructor(config: IConfig) {
    super(config); // this now works :)
  }
}

我不太喜欢用继承的方式提供可扩展性。尽管如此,在这种情况下,我还是希望设计基类,使其显式可扩展,并且在配置输入参数上使用泛型类型约束并导出基类配置类型

// base.ts ---------------------------------------------------------------------
export interface IBaseConfig {
  someProperty: string;
}

export class Base<TConfig extends IBaseConfig = IBaseConfig> {
  constructor(config: TConfig) {
  }
}

// derived.ts ------------------------------------------------------------------
interface IDerivedConfig extends IBaseConfig {
  otherProperty: string;
}

export class Derived extends Base<IDerivedConfig> {
  constructor(config: IDerivedConfig) {
    super(config);
  }
}
注:

IDerivedConfig不会扩展我们从您的提示中获得的IConfig:type BaseConfigType=ConstructorParameters[0],以便完全掌握并防止基本配置中的更改传播到客户端中的所有构建站点。 派生类实现了基而不是扩展基。尽管如此,没有必要对其进行编码,但在开始时要确保类型兼容性。那么移除它更安全。如果基类发生更改,我们可以选择传播更改,或者只将我们的类编码为。 派生类有一个静态工厂方法来创建它,该函数调用定义内联私有只读基对象的私有构造函数。 在Derived.create方法中,baseConfig是通过推断隐式键入的。代码是安全的,因为编译器阻止我们将不兼容的参数传递给基构造函数。
这就是方法:-我完全同意,但这是假设您可以更改base.ts类和接口定义。@Anupheaus:当我们无法更改base.ts时,我添加了一个带有另一个选项的编辑部分。
// base.ts ---------------------------------------------------------------------
interface IConfig {
  someProperty: string;
}

export class Base {
  constructor(config: IConfig) { }
  compute(arg: any): string { return 'any-string'; }
  do(): void {}
}

// derived.ts ------------------------------------------------------------------
export interface IDerivedConfig { /* TBD */ }

export class Derived {
  static create(config: IDerivedConfig): Derived {
    const baseConfig = {} as any /* TODO: replace `{} as any` with the custom mapping from `config` to a base config object. */;
    const base = new Base(baseConfig);
    return new Derived(base);
  }

  private constructor(
    private readonly base: Base,
  ) { }

  compute(arg: any) {
    return this.base.compute(arg);
  }

  do() {
    this.base.do();
  }
}