Почему компилятор неявное приведение типов не работает для свойств с буквальным типом, которые являются реализациями расширенного интерфейса?

#javascript #typescript #inheritance

#typescript

Вопрос:

Почему компилятор неявное приведение типов не работает для свойств с буквальным типом, которые являются реализациями расширенного интерфейса?

Пример:

 // typescript 3.4.5

interface INumContainer {
  num?: 1 | 2;
}

class myClass implements INumContainer {
  // does not compile
  // error TS2416: Property 'num' in type 'myClass' is not assignable to the same property in base type 'INumContainer'.
  //   Type 'number' is not assignable to type '1 | 2 | undefined'.
  num = 1;

  anotherNum: 1 | 2 = 1; // compiles
}
  

Ответ №1:

Члены класса контекстуально не типизируются типами, для расширения или реализации которых они объявлены, по крайней мере, начиная с TS3.7. extends implements Объявления or приводят к проверке типа расширяемого / реализующего класса, но это происходит позже. Это долгое время было проблемой.

Здесь происходит то, что литеральные типы, подобные 1 или 2 number расширенные, содержат типы, подобные, если они не находятся в нерасширяющемся контексте. И поскольку myClass.num контекстуально не типизируется INumContainer["num"] , он расширяется до number , что считается несовместимым.

Исходная проблема, связанная с этим для свойств, — microsoft / TypeScript # 3667. Была попытка исправить это, но в конечном итоге она была отклонена / оставлена из-за плохой совместимости с некоторыми реальными библиотеками кода.

И с тех пор мало что произошло. Похоже, что в настоящее время открытым вопросом по этой теме является microsoft / TypeScript #32082, поэтому, если вы хотите увидеть это решение, вы можете перейти к этому вопросу и дать ему 👍 или какое-либо другое подтверждение поддержки.

До тех пор вам просто придется избыточно аннотировать свои инициализаторы. Извините, у меня нет лучшего ответа для вас. Надеюсь, это поможет; удачи!