web-dev-qa-db-ja.com

Keyof推論文字列|キーが文字列のみの場合の数値

AbstractModelを次のように定義します。

export interface AbstractModel {
   [key: string]: any
}

次に、タイプKeysを宣言します。

export type Keys = keyof AbstractModel;

Keysタイプを持つものはすべて、文字列として一義的に解釈されると予想されます。次に例を示します。

const test: Keys;
test.toLowercase(); // Error: Property 'toLowerCase' does not exist on type 'string | number'. Property 'toLowerCase' does not exist on type 'number'.

これはTypeScript(2.9.2)のバグですか、それとも何か不足していますか?

14
don

TypeScript 2.9のリリースノートで定義されているように、文字列インデックスシグネチャを持つインターフェイスのキーを指定すると、文字列と数値の和集合が返されます

オブジェクトタイプXが与えられると、keyof Xは次のように解決されます。

Xに文字列インデックスシグニチャが含まれる場合、keyof Xは文字列、数値、およびシンボルのようなプロパティを表すリテラルタイプの結合です。

Xに数値インデックスシグニチャが含まれる場合、keyof Xは数値と文字列のようなプロパティおよびシンボルのようなプロパティを表すリテラルタイプの和集合です。

keyof Xは、文字列のような、数値のような、シンボルのようなプロパティを表すリテラル型の結合です。

ソース

これは、JavaScriptがオブジェクトのインデックス作成時に数値を文字列に変換するためです。

[..]数値でインデックスを作成する場合、JavaScriptは実際にオブジェクトにインデックスを作成する前に文字列に変換します。つまり、100(数字)でのインデックス付けは、 "100"(文字列)でのインデックス付けと同じことなので、2つは一貫している必要があります。

ソース

例:

let abc: AbstractModel = {
    1: "one",
};

console.log(abc[1] === abc["1"]); // true

文字列キーのみが必要な場合は、次のようにインターフェイスから文字列キーのみを抽出できます。

type StringKeys = Extract<keyof AbstractModel, string>;

const test: StringKeys;
test.toLowerCase(); // no error

また、TypeScriptコンパイラには、keyofの2.9より前の動作を取得するオプションがあります。

keyofStringsOnly(ブール値)デフォルトfalse

keyofを文字列値のプロパティ名のみに解決します(数字や記号は不可)。

ソース

19
jmattheis

同様の問題に直面しました。キーを文字列に強制することで解決しました:

_export type Keys = keyof AbstractModel & string;
_

他のオプションは、キーを文字列に変換することです:test.toString().toLowercase()

3
madox2