Help us understand the problem. What is going on with this article?

TypeScript:インデックスシグネチャが型安全を破壊する例

More than 1 year has passed since last update.

TypeScriptには、添え字アクセスに対して型注釈をつけるための Index Signatureという仕組みがあります。

これについて、某ライブラリの型定義でギョッとする使われ方をしていて、修正PRを出してアクセプトしていただいたのですが、ちょっと面白い(恐ろしい)事例だったので紹介。

インデックスシグネチャとは

プロパティへの添え字アクセス(C# でいうところのインデクサー)に対する型情報を定義します。

たとえば、数値をキーにして文字列を保持する連想配列であれば、こんなふうに定義できます。

interface NumStrDictionary {
    [key: number]: string;
}

使用イメージ。

//初期化
const dic: NumStrDictionary = {
    1: "いち",
    2: ""
}
//更新
dic[10] = "じゅう";

//取得
console.log(dic[1]);    //いち
console.log(dic[10]);   //じゅう
console.log(dic[3]);    //undefined

キーがstringの場合、ドットアクセスが可能

js使いにとっては「そりゃそうでしょ」という感じなのかもしれませんが、このインデックスシグネチャのキーがstringである場合、 .キー名 という書式でのアクセスが可能なんです(TypeScript 2.2以降:参考

interface StrStrDictionary {
    [key: string]: string;
}

const dic: StrStrDictionary = {}

dic.hoge = "ほげ";
dic["huga"] = "ふが";

console.log(dic["hoge"]);   //ほげ
console.log(dic.huga);      //ふが

これが恐ろしいことに・・・。

存在しないプロパティに対するコンパイルエラーが効かなくなる

前の例を見てもらえればわかるとおり、 .キー名 で任意のキーに対する値を取得/設定できるということはつまり、 stringをキーとするインデックスシグネチャが定義されたinterfaceに対しては、タイポ等に対するコンパイルチェックが一切効かない ということです。

例のように、インデックスシグネチャのみが定義されたinterfaceであればさほど問題はないかもしれません。

しかし、私の遭遇した某ライブラリでは、そのコア機能の多くを定義するすべてのinterfaceの継承元interfaceとして、しかも最悪なことに any型を返すインデックスシグネチャが定義されていた ため、そのライブラリのほぼすべてのinterfaceにおいて、一切のコンパイルチェックが効かない状態となっていました。

interface Extendable {
    // 拡張できるよ!みたいな意図だったらしい
    [key: string]: any;
}

interface CoreFunctions extends Extendable {
    func1(): void;
    func2(): void;
}

const core: CoreFunctions = getCoreFunc();
core.func1();
core.func2();
core.func3();       //<- 書けちゃう
core.func4.aaa.bbb; //<- なんでも書けちゃう

しかし意外と気づかない

しかしこれが、こんな状態でも意外と気づかないものでした。
というのは、Visual Studio Codeのような高機能エディタであれば、存在するプロパティに対する補完自体は快適に機能するため、存在しないプロパティ名をタイプしてしまう機会というのが、まずほとんどないんですね。

なので気づかないでいると特にこわいのは、後からリファクタリングなどでプロパティ名を変更するようなケース。
どうせコンパイルエラーになるだろうと思っていたらならないので、実行時に初めて気がつくことになります。

というわけで、インデックスシグネチャを使用する際は注意しましょうという話でした。

aakasaka
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした