Discriminated Unionsでその他を定義したい
以下のようなDiscriminated Unionsのサンプルを少し変えたinterface( kind 以外が data というオブジェクトに入っている)と関数を書きました。
interface Square {
kind: "square";
data: {
size: number;
}
}
interface Rectangle {
kind: "rectangle";
data: {
width: number;
height: number;
}
}
interface Circle {
kind: "circle";
data: {
radius: number;
}
}
type Shape = Square | Rectangle | Circle;
function area(s: Shape) {
switch (s.kind) {
case "square": return s.data.size * s.data.size;
case "rectangle": return s.data.height * s.data.width;
case "circle": return Math.PI * s.data.radius ** 2;
}
}
これはもちろん正しいTypeScriptです。
この area 関数を
interface AnyShape {
kind: string;
data: object;
}
な任意の入力を受け付けるようにして適当なエラーを返すようにしたいと考えています。
そこで area 関数を以下のようにすると
function area(s: Shape) {
switch (s.kind) {
case "square": return s.data.size * s.data.size;
case "rectangle": return s.data.height * s.data.width;
case "circle": return Math.PI * s.data.radius ** 2;
default: throw new Error(`Not support ${s.kind}: ${JSON.stringify(s.data)}`);
}
}
default 時の s が never となります。
そこで Shape の定義を
type Shape = Square | Rectangle | Circle | AnyShape;
(playground)
とすると case 中の s が該当する Shape もしくは AnyShape となりコンパイルが通らなくなります。
このような area 関数を定義する場合、適切な方法を教えていただけると助かります。できれば、JavaScriptとしては変更しない(型アノテーションの書き換え)のみで乗り切る方法が知りたいです(type predicateを使い function isSquare(s: AnyShape): s is Square { return s.kind === 'square'; } みたいなのを書き並べたらできそうな気はしているので)。
(現状の機能だと不可能な気はしていますが)特に他の Shape には該当しない AnyShape が定義できるなら特に知りたいです。