inと判別で絞り込む
オブジェクトには typeof が効かない
前回は typeof で型を絞り込みました。ところが相手がオブジェクトだと、この手が使えません。
type PublishedWork = { title: string; url: string };
type DraftWork = { title: string; memo: string };
type PortfolioWork = PublishedWork | DraftWork;公開済みの作品には公開先の url があり、下書きには自分用の memo があります。しかし typeof はどちらに対しても "object" としか答えません。区別できないのです。
in でプロパティの有無を見る
オブジェクトを見分けるときは、そのオブジェクトが特定のプロパティを持っているかどうかで判定します。使うのは in 演算子です。
function workLine(work: PortfolioWork): string {
if ("url" in work) {
return work.title + " " + work.url;
}
return work.title + "(下書き)";
}"url" in work が true の枝では work が PublishedWork に確定するので、work.url を読めます。抜けたあとは DraftWork に確定するので、work.memo を読めます。
絞り込む前に work.url と書くと、当然止まります。
function workLine(work: PortfolioWork): string {
return work.url;
// エラー Property 'url' does not exist on type 'PortfolioWork'.
}work.title のほうは、どちらの型も持っているので絞り込まなくても読めます。
判別プロパティを置くやり方
プロパティの有無に頼らず、種類を表す目印を最初から入れておく書き方もあります。
type PublishedWork = { kind: "published"; title: string; url: string };
type DraftWork = { kind: "draft"; title: string };
type PortfolioWork = PublishedWork | DraftWork;
function workLine(work: PortfolioWork): string {
if (work.kind === "published") {
return work.title + " " + work.url;
}
return work.title + "(下書き)";
}この kind を判別プロパティと呼びます。リテラル型で値を固定してあるので、比較するだけで絞り込みが効きます。
自分で型を設計できるなら判別プロパティを選びます。あとから型を足しても壊れにくいからです。目印を足せない外部データには in を使います。
手を動かす
演習では、公開済みの作品と下書きの作品を見分けて、一覧の 1 行を作ります。型はすでに定義してあるので、絞り込みの分岐を書いてください。
要件
inを使って公開済みか下書きかを見分ける- 公開済みならタイトルと URL を半角スペースでつなぐ
- 下書きならタイトルのうしろに
(下書き)を付ける - 型の定義は変えない
入出力例
workLine({"title":"プロフィールサイト","url":"https://example.com/profile"}) → "プロフィールサイト https://example.com/profile"
workLine({"memo":"配色を検討中","title":"自己紹介カード"}) → "自己紹介カード(下書き)"
workLine({"title":"スキル一覧の表","url":"https://example.com/skills"}) → "スキル一覧の表 https://example.com/skills"
workLine({"memo":"","title":"配色メモ"}) → "配色メモ(下書き)"ヒント
編集 LuaGate編集部