noImplicitAnyフラグを有効にしてtypescriptをコンパイルするときに、「オブジェクトタイプのインデックスシグネチャには暗黙的に「any」タイプがあります」というエラーを防ぐにはどうすればよいですか?


309

私は常に--noImplicitAnyフラグを使用してTypescriptをコンパイルします。これは、型チェックをできるだけ厳しくしたいので意味があります。

私の問題は、次のコードでエラーが発生することIndex signature of object type implicitly has an 'any' typeです:

interface ISomeObject {
    firstKey:   string;
    secondKey:  string;
    thirdKey:   string;
}

let someObject: ISomeObject = {
    firstKey:   'firstValue',
    secondKey:  'secondValue',
    thirdKey:   'thirdValue'
};

let key: string = 'secondKey';

let secondValue: string = someObject[key];

注意すべき重要な点は、キー変数はアプリケーションの他の場所から取得され、オブジェクト内の任意のキーにすることができるという考え方です。

私は明示的に型をキャストしてみました:

let secondValue: string = <string>someObject[key];

それとも私のシナリオは不可能--noImplicitAnyですか?

回答:


337

インデックスシグネチャを追加すると、TypeScriptにタイプが何であるかを知らせます。

あなたのケースでは [key: string]: string;

interface ISomeObject {
    firstKey:      string;
    secondKey:     string;
    thirdKey:      string;
    [key: string]: string;
}

ただし、これにより、すべてのプロパティタイプがインデックスシグネチャと一致するように強制されます。プロパティはすべてaなので、string機能します。

インデックスシグネチャは、配列と「辞書」パターンを記述する強力な方法ですが、すべてのプロパティが戻り値の型と一致することも強制します。

編集:

タイプが一致しない場合は、共用体タイプを使用できます [key: string]: string|IOtherObject;

共用体型を使用する場合は、TypeScriptで定義するのではなく、型を推測する方がよいでしょう。

// Type of `secondValue` is `string|IOtherObject`
let secondValue = someObject[key];
// Type of `foo` is `string`
let foo = secondValue + '';

ただし、インデックスシグネチャにさまざまなタイプが多数ある場合は、少し面倒になる可能性があります。代わりにany署名で使用することです。[key: string]: any;次に、上記と同じように型をキャストする必要があります。


そして、あなたのインターフェースがインターフェースISomeObject {firstKey:string; secondKey:IOtherObject; }これは不可能だと思いますか?
Jasper Schulte、2015年

ありがとう!任意のタイプと1つのケースに1つのタイプをキャストすることの組み合わせは、販売済みの方法のようです。
Jasper Schulte、2015年

こんにちは、「anyObject [key:Object] ['name']」の処理方法は?
Code_Crash

または、_obj = {};のように言います。let _dbKey = _props [key] ['name']; _obj [_dbKey] = this [key]; ここで_propsはオブジェクトであり、object [key]もnameプロパティを持つオブジェクトを返します。
Code_Crash

180

エラーを回避する別の方法は、次のようなキャストを使用することです。

let secondValue: string = (<any>someObject)[key]; (括弧に注意)

唯一の問題は、にキャストしているため、これがタイプセーフではなくなったことですany。ただし、いつでも正しいタイプにキャストバックできます。

ps:私はtypescript 1.7を使用していますが、以前のバージョンはわかりません。


20
tslint警告を避けるために、あなたも使用することができます:let secondValue: string = (someObject as any)[key];
briosheje

96

TypeScript 2.1では、この問題を処理するエレガントな方法が導入されました。

const key: (keyof ISomeObject) = 'secondKey';
const secondValue: string = someObject[key];

keyofキーワードを使用して、コンパイル段階ですべてのオブジェクトプロパティ名にアクセスできます(changelogを参照)。

string変数の型をに置き換えるだけですkeyof ISomeObject。これでコンパイラkeyは、変数にからのプロパティ名のみを含めることが許可されていることを認識しますISomeObject

完全な例:

interface ISomeObject {
    firstKey:   string;
    secondKey:  string;
    thirdKey:   number;
}

const someObject: ISomeObject = {
    firstKey:   'firstValue',
    secondKey:  'secondValue',
    thirdKey:   3
};

const key: (keyof ISomeObject) = 'secondKey';
const secondValue: string = someObject[key];

// You can mix types in interface, keyof will know which types you refer to.
const keyNumber: (keyof ISomeObject) = 'thirdKey';
const numberValue: number = someObject[keyNumber];

typescriptlang.orgのライブコード(設定noImplicitAnyオプション)

より多くのkeyof使用法でさらに読む。


6
ただし、次のように宣言keyした場合は機能しませんconst key = (keyof ISomeObject)= 'second' + 'Key'
2018

55

次のtsconfig設定を使用すると、これらのエラーを無視できます。trueに設定します。

suppressImplicitAnyIndexErrors

インデックスシグネチャが不足しているインデックスオブジェクトのnoImplicitAnyエラーを抑制します。


14
それはあなたがすべきではないことです-おそらくあなたのチームの誰かがこのコンパイラオプションを明示的に設定して、コードをより完全なものにしています!
atsu85 2016

12
これがこのオプションの目的とまったく同じではないことに同意し--noImplicitAnyます。で括弧表記を許可します。opの質問に完全に一致します。
Ghetolay 2016年

4
@Ghetolayに同意します。これは、インターフェースの変更が不可能な場合の唯一のオプションでもあります。たとえば、のような内部インターフェースを使用しますXMLHttpRequest
Marco Roy

1
@Ghetolayにも同意します。これがPedro Villa Verdeの回答と質的にどのように異なるのか興味があります(コードが見苦しくないという事実は別です)。文字列を使用してオブジェクトプロパティにアクセスすることは可能な限り避けるべきであることは誰もが知っていますが、リスクを理解しながら自由を享受することもあります。
スティーブンポール

それは単なるトレードオフです。好きなものを選択してください。エラーの少ない領域と厳密なインデックスアクセス、またはエラーの多い領域を用意して未知のインデックスに簡単にアクセスできます。TS2.1 keyofオペレーターは、すべてを厳格に保つのに役立ちます。Piotr の回答をご覧ください。
trusktr 2018

24

上記の「keyof」ソリューションは機能します。しかし、変数が1回だけ使用される場合、たとえばオブジェクトをループするなどの場合は、型キャストすることもできます。

for (const key in someObject) {
    sampleObject[key] = someObject[key as keyof ISomeObject];
}

ありがとう。これは、別のオブジェクトのキーを反復するときの任意のキーアクセスに対して機能します。
bucabay

19

使用する keyof typeof

const cat = {
    name: 'tuntun'
}

const key: string = 'name' 

cat[key as keyof typeof cat]

7

@Piotrレヴァンドフスキの答えに似ていますが、中forEach

const config: MyConfig = { ... };

Object.keys(config)
  .forEach((key: keyof MyConfig) => {
    if (config[key]) {
      // ...
    }
  });

これをどのように機能させましたか?同じことを試していますが(ts 3.8.3)、次のエラーがスローされますArgument of type '(field: "id" | "url" | "name") => void' is not assignable to parameter of type '(value: string, index: number, array: string[]) => void'。私のコードのルックスがとても好きでObject.keys(components).forEach((comp: Component) => {...}、どこComponentタイプ(のようですMyConfig)。
theGirrafish

6

このようにオブジェクトを宣言します。

export interface Thread {
    id:number;
    messageIds: number[];
    participants: {
        [key:number]: number
    };
}

6

インデクサーなし?次に、自分で作成してください!

これを、オブジェクトシグネチャを定義する簡単な方法としてグローバルに定義しました。Tすることができany、必要な場合:

type Indexer<T> = { [ key: string ]: T };

indexerクラスのメンバーとして追加するだけです。

indexer = this as unknown as Indexer<Fruit>;

だから私はこれで終わります:

constructor(private breakpointResponsiveService: FeatureBoxBreakpointResponsiveService) {

}

apple: Fruit<string>;
pear: Fruit<string>;

// just a reference to 'this' at runtime
indexer = this as unknown as Indexer<Fruit>;

something() {

    this.indexer['apple'] = ...    // typed as Fruit

これを行う利点は、適切な型が返さ<any>れることです。使用する多くのソリューションでは、型付けが失われます。これはランタイム検証を実行しないことに注意してください。存在するかどうかわからない場合でも、存在するかどうかを確認する必要があります。

過度に注意したい場合、strictこれを使用すると、明示的に未定義のチェックを行う必要があるすべての場所を明らかにすることができます。

type OptionalIndexed<T> = { [ key: string ]: T | undefined };

私がどこかから文字列プロパティとして持っている場合、私は通常それが有効であることを知っているので、私は通常これが必要であるとは思いません。

この方法は、インデクサーにアクセスする必要のあるコードが多数あり、タイピングを1か所で変更できる場合に特に便利です。

注:私はstrictモードを使用していますunknown。これは間違いなく必要です。

コンパイルされたコードは単になのでindexer = this、typescriptが作成する場合と非常に似てい_this = thisます。


1
Record<T>typeを代わりに使用できる場合もあります-現在、これの詳細を調査することはできませんが、一部の限られた場合には、よりうまく機能する場合があります。
Simon_Weaver

5

「インデクサー」インターフェースを定義するインターフェースを作成する

次に、そのインデックスでオブジェクトを作成します。

注:これでも、各項目のタイプの強制に関して他の回答で説明されているのと同じ問題が発生しますが、それは多くの場合、まさにあなたが望んでいることです。

必要に応じてジェネリック型パラメーターを作成できます。 ObjectIndexer< Dog | Cat>

// this should be global somewhere, or you may already be 
// using a library that provides such a type
export interface ObjectIndexer<T> {
  [id: string]: T;
}

interface ISomeObject extends ObjectIndexer<string>
{
    firstKey:   string;
    secondKey:  string;
    thirdKey:   string;
}

let someObject: ISomeObject = {
    firstKey:   'firstValue',
    secondKey:  'secondValue',
    thirdKey:   'thirdValue'
};

let key: string = 'secondKey';

let secondValue: string = someObject[key];

Typescript Playground


ジェネリック型を定義するときに、これをジェネリック制約で使用することもできます。

export class SmartFormGroup<T extends IndexableObject<any>> extends FormGroup

次にT、クラス内にインデックスを付けることができます:-)


これDictionaryを表すための標準の「組み込み」インターフェースはないと思いますが{ [key: string]: T }、ある場合は、この質問を編集してを削除してくださいObjectIndexer
Simon_Weaver

3

キーが文字列であるタイプを宣言し、値は任意であることができ、このタイプでオブジェクトを宣言すると、lintは表示されません

type MyType = {[key: string]: any};

だからあなたのコードは

type ISomeType = {[key: string]: any};

    let someObject: ISomeType = {
        firstKey:   'firstValue',
        secondKey:  'secondValue',
        thirdKey:   'thirdValue'
    };

    let key: string = 'secondKey';

    let secondValue: string = someObject[key];

1

今日のより良い解決策は、型を宣言することです。お気に入り

enum SomeObjectKeys {
    firstKey = 'firstKey',
    secondKey = 'secondKey',
    thirdKey = 'thirdKey',
}

let someObject: Record<SomeObjectKeys, string> = {
    firstKey:   'firstValue',
    secondKey:  'secondValue',
    thirdKey:   'thirdValue',
};

let key: SomeObjectKeys = 'secondKey';

let secondValue: string = someObject[key];

1

Typescript 3.1を使用して3つのステップで見つけることができる最も簡単な解決策は、次のとおりです。

1)インターフェイスを作成する

interface IOriginal {
    original: { [key: string]: any }
}

2)入力したコピーを作成する

let copy: IOriginal = (original as any)[key];

3)どこでも使用(JSXを含む)

<input customProp={copy} />
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.