Первое, с чем нам нужно иметь дело, это связать фигуры с их соответствующими видами.Ваше оригинальное решение:
/**
* Bad — doesn't bind the `Shape` with its `kind`. It allows calling `fetch<Square>('circle', 'foo')`.
*/
declare function fetch<T extends Shape>(type: Shape['kind'], id: string): T;
Вместо этого скажите TypeScript, что type
должен быть не просто какого-либо вида, а именно того вида, который мы сейчас рассматриваем.
/**
* Better: the `kind` is bound with its corresponding `Shape`. The downside: The exact return type is not inferred.
*/
declare function fetch<T extends Shape>(type: T['kind'], id: string): T;
const oups = fetch<Square>('circle', 'foo'); // $ExpectError
const shape = fetch('circle', 'foo'); // $ExpectType Shape
Это лучше, но тип возвращаемого значения - Shape
.Мы можем добиться большего, указав перегрузки для вашей функции:
/**
* Using overloads can help you determine the exact return type.
*/
declare function fetch(type: 'circle', id: string): Circle;
declare function fetch(type: 'square', id: string): Square;
declare function fetch(type: 'rectangle', id: string): Rectangle;
const circle = fetch('circle', 'foo'); // $ExpectType Circle
Это даст вам точные типы возврата, но за счет необходимости писать больше кода.Можно также утверждать, что существует некоторая избыточность - связь между формой и ее видом уже инкапсулирована в ее интерфейсе, поэтому повторение ее в виде перегрузки кажется менее совершенным.