打字稿:在类中扩展“ this”

时间:2020-03-15 19:15:14

标签: typescript class this extends

我有一个类Foo,我想用我拥有的一些文字对象来动态扩展它。如何保持this键入,而无需在单独的界面中手动重复文字对象的键

const someLiteralObject = {
  key1: 'foo',
  key2: 'bar',
  //  ...lots of more keys
}

class Foo {
   constructor(){
      Object.assign(this, someLiteralObject)
   }
   test() {
    console.log(this.key1); //error: Property 'key1' does not exist on type 'Foo'
   }
}

const test = new Foo();
console.log(test.key1); //error: Property 'key1' does not exist on type 'Foo'

2 个答案:

答案 0 :(得分:2)

编辑:我建议您研究Mixins in Typescript,并研究那里介绍的Object.assignapplyMixins助手之间的区别。也许正是您实际需要的设计模式。

这是一个肮脏但类型强的解决方案,它使用文字对象,而不是按要求重复所有键。内联说明和TypeScript Playground link

// Hide these helpers away in your `utils.ts` somewhere, see below what they do.
/**
 * Gives Constructor given a instance, like inverse of `InstanceType`.
 *
 * Second optional parameter is argument tuple for the `constructor()`.
 *
 * @todo this interface lacks signature for static methods/properties.
 */
export interface IConstructor<T extends object = object, TA extends unknown[] = unknown[]> {
    new(...args: TA): T
}
/**
 * Overrrides a class to return a instance that includes the given mixin.
 */
export type ClassWithMixin<T extends IConstructor, TMixin extends object> =
    IConstructor<InstanceType<T> & TMixin, ConstructorParameters<T>>


// A mixin many keys and/or methods. Use `typeof someLiteralObject` to use it as interface.
const someLiteralObject = {
  key1: 'foo',
  key2: 'bar',
} as const  // <-- `as const` is optional, but handy.

// `this:` type tells method internal scope that `this` is more than TS thinks by default.
class FooPure {
   constructor(){
      Object.assign(this, someLiteralObject)
   }
   test(this: this & typeof someLiteralObject) {
    console.log(this.key1)
   }
}
// And `ClassWithMixin` type tells all other codebase that `Foo` is more than `FooHidden`.
const Foo = FooPure as ClassWithMixin<typeof FooPure, typeof someLiteralObject>

// Works as expected.
const foo = new Foo()
console.log(foo.key1)
foo.test()
class Bar extends Foo {
  constructor() {
    super()
    this.test()
  }
}
console.log(new Bar())

答案 1 :(得分:0)

强类型输入方式:

class Some { // <= This is representing your Object
        key1: string;
        key2: string;
}

const someLiteralObject: Some = { // <= As you can see it is of type Some
  key1: 'foo',
  key2: 'bar',
}

class Foo extends Some { // <= Tell TS we are using all the keys from Some
   constructor(){
      super(); // <= needed for ts, useless as we did not define a constructor in Some
      Object.assign(this, someLiteralObject);
   }
   test() {
    console.log(this.key1); // Yeah!
   }
}

const test = new Foo();
console.log(test.key1); // No error!
test.test(); // works fine!

笨拙的方式(例如,当您不知道对象将拥有哪些键时)

const someLiteralObject = {
  key1: 'foo',
  key2: 'bar',
}

class Foo {
   constructor(){
      Object.assign(this, someLiteralObject)
   }
   test() {
    console.log((this as any).key1); // tell ts to be unsure about the type of this
   }
}

const test = new Foo();
console.log((test as any).key1); // tell ts to be unsure about the type of this