Typescript реализует интерфейс с 57 ключами: использование распространителя? - PullRequest
0 голосов
/ 22 мая 2019

Мне нужно создать класс, который реализует интерфейс с 57 свойствами (на самом деле это схема googleapi adminsdk).Я хотел бы избежать перепечатывания всего определения интерфейса при создании класса.Думал об использовании оператора распространения, но он не удался

Легкий пример только с 3 свойствами:

interface myInt {
   field1:string;
   field2:string;
   field3?:number;
}

class theClass implements myInt{
   private theFields:myInt
   constructor(data:myInt)
   {
     this.theFields = {{}, ...data}   <---incorrect
   }
}

1 Ответ

1 голос
/ 23 мая 2019

Ну, здесь кое-что происходит. Начиная с вашего интерфейса:

interface MyInt {
  field1: string;
  field2: string;
  field3?: number;
}

ваш первоначальный класс был чем-то содержащим a MyInt, на самом деле он не реализовывал этого. «Правильный» способ хранить MyInt в классе:

class HasMyInt {
  private theFields: MyInt;
  constructor(data: MyInt) {
    this.theFields = { ...data }; // spread data into this.theFields
  }
}

Возможно, вам этого достаточно, но тогда HasMyInt сам по себе не является экземпляром интерфейса MyInt. Если вы хотите создать класс, который является экземпляром, то «правильный» способ сделать это, к сожалению, включает избыточные объявления свойств, а также определенные утверждения присваивания для подавления любых предупреждений с помощью --strictPropertyInitialization:

class IsMyIntManual implements MyInt {
  // need these, unfortunately:
  field1!: string;
  field2!: string;
  field3?: number;
  constructor(data: MyInt) {
    Object.assign(this, data); // spread data into this
  }
}

Использует Object.assign() вместо оператора распространения объекта, поскольку позволяет изменять существующий целевой объект (this) вместо возврата нового.

Если вы действительно хотите избежать избыточных объявлений свойств, вы можете создать своего рода «фабрику базовых классов», которая с учетом типа объекта T создает функцию-конструктор, которая копирует свойства из аргумента типа T в сам. Обратите внимание, что для компиляции здесь требуется утверждение типа , поскольку TypeScript не распознает функцию конструктора в стиле ES5 как new способную.

function BaseClass<T extends object>() {
  return (function(this: T, data: T) {
    Object.assign(this, data);
  } as any) as new (arg: T) => T; // need assertion
}

Это позволяет легко создавать IsMyInt, расширяя BaseClass<MyInt>():

// this implements IsMyInt
class IsMyIntAutomatic extends BaseClass<MyInt>() {}

И если вам нужно добавить больше функций в этот класс, вы можете сделать это:

class ExtendingIsMyInt extends BaseClass<MyInt>() {
  public anotherProperty: number;
  constructor(data: MyInt, anotherProperty: number) {
    super(data);
    this.anotherProperty = anotherProperty;
  }
  method() {
    return this.field2 != this.field1 ? this.field3 || this.anotherProperty : 0;
  }
}

Ссылка на этот код

Хорошо, надеюсь, это поможет. Удачи!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...