This is a valid definition in TypeScript:
type Shape<T> = (
circle: (x: number, y: number, r: number) => T,
rectangle: (x: number, y: number, w: number, h: number) => T
) => T;
function Circle<T>(x: number, y: number, r: number): Shape<T> {
return (_Circle, _Rectangle) => _Circle(x, y, r);
}
function Rectangle<T>(x: number, y: number, w: number, h: number): Shape<T> {
return (_Circle, _Rectangle) => _Rectangle(x, y, w, h);
}
const exampleCircle = Circle(2, 1.4, 4.5);
const exampleRectangle = Rectangle(1.3, 3.1, 10.3, 7.7);
function area(shape: Shape<unknown>): number {
const s = shape as Shape<number>;
return s(
(x, y, r) => Math.PI * r * r,
(x, y, w, h) => w * h
);
}
export function main() {
console.log(area(exampleCircle));
console.log(area(exampleRectangle));
}
Unfortunately I think the cast might be necessary, but happy to see another solution from someone with more typescript expertise.