blue32a
@blue32a (blue32a)

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

[TypeScript] 同じプロパティを持つオブジェクトを異なる型で表現したい

解決したいこと

TypeScriptで、同じプロパティを持つオブジェクトを異なる型で表現したい。

例えば、特定サービスへの接続オプションが複数パターンある状況について、そのパターンをそれぞれ型で表現したいと思っています。
使用すべき接続オプションを型で表明し、使用すべきでない接続オプションを指定できないようにするのが目的です。

※ TypeScriptの仕様などを把握したいので、ドキュメントなども合わせて示していただけると大変助かります。

発生している問題・エラー

型が異なる箇所でエラーになって欲しいが、エラーにならない。

TypeScript: 3.7.5

interface Base {
    a: string,
    b: string,
}
interface Hoge extends Base {}
interface Fuga extends Base {}

function getHoge(): Hoge {
    return {
        a: 'a',
        b: 'b',
    };
}

const hoge: Hoge = getHoge();
console.log(hoge);
const fuga: Fuga = getHoge(); // エラーになって欲しい
console.log(fuga);

自分で試したこと

単純なJavaScriptオブジェクトだけを使用している場合(構造型を使用する場合)、 instanceofまたはtypeofにアクセスすることさえできません。

これは「オブジェクトがどのInterfaceを実装しているのかは判定できない」と解釈できそう。

プロパティを追加することで特定の型に制限できるようにはなったが、本来不要なプロパティが増えてしまった。
TypeScriptでは妥当な解決方法だろうか?

typeプロパティを追加してみた
interface Base {
    a: string,
    b: string
}

interface Hoge extends Base {
    type: 'Hoge',
}
interface Fuga extends Base {
    type: 'Fuga',
}

よろしくお願いいたします。

0

2Answer

TypeScriptでは妥当な解決方法だろうか?

はい、その方法が推奨されています。実際には _hogeBrand: any, _fugaBrand: any のような未使用プロパティを定義し、オブジェクトを作るときは型アサーションを使うというやり方もあります。

2Like

Comments

  1. @blue32a

    Questioner

    回答ありがとうございます。

    解決方法の良し悪しが分からなかったので、おかげで先に進めることができました。
    ルールに基づいた未使用プロパティを定義するのが良さそうだったので、それを採用することにしました。

公式サイトのType Compatibilityより

Type compatibility in TypeScript is based on structural subtyping. Structural typing is a way of relating types based solely on their members.

structral subtypingは日本語では構造的部分型と呼ばれている。
引用文にあるように、メンバーのみに基づいた型付け。

typescriptにそのような前提があるため、受け入れるしかないでしょう。

そして解決方法は、最後に書かれたようにリテラル型を付与するしかない気がします。

これはUnion型においてどれが返されたのかを判定を目的とするdiscriminating union(判別可能なUnion型)と呼ばれるものです。一般的な方法です。

公式情報 > https://www.typescriptlang.org/docs/handbook/2/narrowing.html#discriminated-unions

1Like

Comments

  1. @blue32a

    Questioner

    回答ありがとうございます。

    教えていただいたドキュメントを読むことで、期待通りいかなかった理由が理解できました。
    解決方法についても、構造で型が判断されるのであれば異なる構造にするしかなさそうですね。

    大変助かりました。

Your answer might help someone💌