I'm struggling to understand why the switch
statement in my generic function isn't able to cast my types within its branches.
This is my code:
interface Id { id: number; }
enum Kind { square = "square", circle = "circle" }
interface Circle { kind: Kind.circle; radius: number; }
interface Square { kind: Kind.square; size: number; }
type Data = Circle | Square;
type ShapeModel<TData> = Id & TData;
class UnreachableError extends Error { public constructor(guard: never) { super(`Unsupported kind: ${JSON.stringify(guard)}`); } }
function myFunctionGeneric<TData extends Data>(data: TData): ShapeModel<TData> {
switch (data.kind) {
case Kind.circle:
return { ...data, id: 1 };
case Kind.square:
return { ...data, id: 2 };
default:
throw new UnreachableError(data); // <-- UNEXPECTED
// Argument of type 'TData' is not assignable to parameter of type 'never'.
// Type 'Data' is not assignable to type 'never'.
// Type 'Circle' is not assignable to type 'never'.
// ts(2345)
}
}
const myCircleData: Circle = { kind: Kind.circle, radius: 42 };
const mySquareData: Square = { kind: Kind.square, size: 42 };
// I expect this. Passing Circle and expecting to receive ShapeModel<Circle>
const myCircleModel: ShapeModel<Circle> = myFunctionGeneric(myCircleData);
// I expect this. Passing Square and wanting to receive ShapeModel<Square>
const mySquareModel: ShapeModel<Square> = myFunctionGeneric(mySquareData);
This logic works flawlessly without using a generic TData
.
Can someone shed light on why TypeScript struggles to determine the type within the switch branch?