Компилятор на самом деле не выполняет много высокоуровневого анализа, необходимого для подтверждения присваиваемости типов, которые зависят от пока еще неуказанных параметров типа c generi. Внутри реализации storeThing
вы присваиваете значение типа Store<ThingType>[T]
переменной типа Container<T> | undefined
, где T
еще не определено как конкретный тип. И, к сожалению, компилятор не может видеть их как совместимые без указания T
, даже если они совместимы для всех возможных сужений T
.
Это, по сути, ограничение дизайна TypeScript. См. microsoft / TypeScript # 36737 и microsoft / TypeScript # 36349 для похожих проблем такого рода; в обоих случаях компилятор не может следовать связи более высокого порядка между индексированным доступом generi c и другим совместимым типом. Существует существующее открытое предложение, microsoft / TypeScript # 33014 , для лучшей обработки подобных случаев, но неясно, будет ли что-либо реализовано там.
До тех пор, пока это не произойдет нам нужно найти какой-то путь вперед.
Разумный способ двигаться дальше: как только вы хорошо и по-настоящему убедили себя, что то, что вы делаете, совершенно безопасно (и будьте осторожны, это легко чтобы ошибиться и подумать, что что-то безопасно, когда это не так), целесообразно разумное использование утверждения типа :
const container = myStore[thing.type] as Container<T> | undefined; // okay
Этот тип вещи предназначен для утверждения типа: ситуации, в которых вы знаете о типе больше, чем может проверить компилятор. Вы просто утверждаете , что то, что вы делаете, безопасно, и идете дальше. Конечно, есть некоторая опасность, что вы солгали компилятору ... или что ваш код изменится в будущем и превратит ранее правильное утверждение типа в al ie. Утверждения типа переносят бремя проверки безопасности типов с компилятора на разработчика, что хорошо, если вы готовы принять эту ответственность.
Другой способ продолжить: найти некоторые манипуляции с типами, которые достаточно самодостаточны, чтобы компилятор мог следовать вашим рассуждениям даже с неопределенным обобщением c. Это немного искусства, и это не всегда возможно. Вот что я хотел бы сделать, это двухэтапный процесс:
const myStoreNarrowed: Store<T> = myStore; // okay
const container: Container<T> | undefined = myStoreNarrowed[thing.type]; // okay
Компилятор может распознать, что безопасно назначить myStore
переменной типа Store<T>
, которая уже Store<ThingType>
. И затем он может распознать, что когда вы индексируете в Store<T>
с помощью клавиши T
, вы получаете что-то назначаемое для Container<T> | undefined
.
Я бы, вероятно, использовал этот подход, поскольку он все еще дает некоторые гарантии безопасности типов, которые теряются при использовании утверждения типа. Но если ничего не помогает, всегда есть (тщательно продуманное) утверждение типа.
Хорошо, надеюсь, это поможет; удачи!
Детская площадка ссылка на код