Правильный способ назначения полей в конструкторе в производном классе с использованием машинописи и babel с помощью tc39 - PullRequest
0 голосов
/ 17 апреля 2019

Поэтому я столкнулся с проблемой, когда после запуска конструктора значения, присвоенные полю в классе, были перезаписаны с неопределенным значением.

Это было связано с этой проблемой https://github.com/babel/babel/issues/9105, котораяссылки https://github.com/tc39/proposal-class-fields

Код репро приведен ниже.

Я как бы понимаю некоторые причины, по которым это было выбрано, и люди, которые намного лучше знакомы с javascript и нюансами выбора, много спорили об этом, поэтому я предполагаю, что их выбор был лучше, чем я.мог сделать.

Но это кажется действительно ужасным и приводит к тому, что код выглядит так, как будто он должен работать, и если вы отлаживаете его, все работает, пока не завершится конструктор, тогда все не определено.Поэтому мой вопрос в том, как правильно справиться с подобным сценарием?Вы можете обойти это, выполнив это myField: string = this.myField, но этот код чертовски запутывает кого-то, кто не понимает всего, что происходит, и большинство людей считают это бесполезным.

Я пытаюсьчтобы понять, что идиоматический код назначает поля в конструкторе, и все, что я до сих пор придумал, выглядит ужасно и выглядит как анти-шаблон.

class Base {
    constructor(dto?){
        if(dto){
            this.updateFromDTO(dto);
        }
    }

    updateFromDTO(dto) : this{
        return this;
    }
}


class Extends extends Base {
    myField: string;

    updateFromDTO(dto) {
        super.updateFromDTO(dto);
        console.log('I was called');
        this.myField = "weee";
        console.log(this.myField);
        return this;
    }
}

console.log(new Extends("123"));//logs 'I was called', 'weee', then the extends object which has myField as undefined.

Конфигурация Babel для получения такого поведения

const DEVELOPMENT = 'production' !== process.env.NODE_ENV

module.exports = {
    presets: [
        ["@babel/preset-env", {useBuiltIns: "entry"}],
        "@babel/preset-react",
        "@babel/typescript"
    ],
    plugins: [
        "@babel/plugin-proposal-class-properties",
        "@babel/plugin-proposal-export-default-from",
        "@babel/plugin-syntax-dynamic-import",
        ["@babel/plugin-transform-runtime", {"regenerator": true}],
        "@babel/plugin-transform-classes",
    ],
}

1 Ответ

0 голосов
/ 30 мая 2019

Обходной путь к https://github.com/babel/babel/issues/9105, который работает как с tsc, так и с babel, - объединение деклараций.

в вашем случае:

  class Base {
    constructor(dto?: any) {
      if (dto) {
        this.updateFromDTO(dto);
      }
    }

    updateFromDTO(dto: any): this {
      return this;
    }
  }

  // using declaration merging
  interface Extends {
    myField: string;
  }
  class Extends extends Base {
    updateFromDTO(dto: any) {
      super.updateFromDTO(dto);
      console.log("I was called");
      this.myField = "weee";
      console.log(this.myField);
      return this;
    }
  }

в более простом примере:

  interface A {}
  interface B {}

  class Base {
    prop: A | B | null = null;
  }

  class Sub1 extends Base {
    prop!: A | null; // type narrowed
  }

  // using declaration merging
  interface Sub2 {
    prop: A | null; // type narrowed
  }
  class Sub2 extends Base {
  }
  console.log("without declaration merging");
  console.log(`${new Sub1().prop}`); // tsc: null, babel: undefined
  console.log("with declaration merging");
  console.log(`${new Sub2().prop}`); // tsc: null, babel: null

Объявление, объединяющееся здесь, сообщает Typecript о суженном типе, но не добавляет свойство в Sub2, которое @ babel / typescript вставляет в undefined.

...