В настоящее время это ограничение TypeScript: неразрешенные условные типы, то есть те, которые зависят от еще не определенного параметра универсального типа, непрозрачны для компилятора;он действительно не может видеть, что ему присваивается какое-то значение. Тип InstanceType<T>
является определенным следующим образом:
type InstanceType<T extends new (...args: any) => any> =
T extends new (...args: any) => infer R ? R : any;
Это условный тип, а внутри реализация factory()
, тип InstanceType<VehicleTypes[T]>
не разрешен, так как T
не указан.
Существует несколько открытых проблем GitHub с предложениями по упрощению работы с такими неразрешенными условными типами, но в настоящее время ни один из них не реализован (по состоянию на TS3.7). Вот несколько ссылок на них, если вы достаточно внимательны, чтобы пойти туда и дать им ? или иным образом отстаивать их:
Сейчас я бы сказал, что либо используйте утверждение типа, как вы, или найдите способ представления вашего типа способом, который не зависит от условных типов. Один из возможных путей продвижения вперед заключается в том, чтобы заметить, что конструкторам классов в TypeScript присваивается свойство prototype
того же типа, что и их тип экземпляра. Это немного странно и не совсем правильно, так как у фактического прототипа не будет никаких свойств только для экземпляра, но так оно и есть, и вряд ли изменится .
Таким образом, вы можете сделать свой собственный InstanceType
, который использует этот факт:
type MyInstanceType<T extends { prototype: any }> = T['prototype'];
И затем вы можете написать
function factory<T extends keyof VehicleTypes>(name: T): MyInstanceType<VehicleTypes[T]> {
let ctor: VehicleTypes[T] = CTORS[name];
return new ctor();
}
без ошибок, и вы все равно получите проверку типаожидайте:
let abc = factory('bike');
abc.ride = 5; // type checks ok
Надеюсь, это поможет;удачи!
Ссылка на код