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
が定義できるなら特に知りたいです。