0
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

posted at

error TS7017: Element implicitly has an 'any' type because type 'XXXXX' has no index signature.を解決する

コンパイラオプション--noImplicitAnyが有効化されていないTypeScriptだと次のコードはコンパイルエラーにならない。

// `strict`か`noImplicitAny`が有効だとコンパイルエラーになる
function calculatePoint(basePoint: number, grade: string): number {
    const factor = {
        'Bronze': 1.0,
        'Silver': 1.5,
        'Gold': 2.0,
    };
    return factor[grade] * basePoint;
}

--noImplicitAnyを有効にすると、このコードはコンパイルエラーになる。エラーログはこんな感じ。

error TS7017: Element implicitly has an 'any' type because type '{ 'Bronze': number; 'Silver': number; 'Gold': number; }' has no index signature.

このコンパイルエラーを解決する。

解決策1

手っ取り早く解決するには、factorany型を明示する。

function calculatePoint(basePoint: number, grade: string): number {
    const factor: any = {
        'Bronze': 1.0,
        'Silver': 1.5,
        'Gold': 2.0,
    };
    return factor[grade] * basePoint;
}

ただこれは問題点を抱えている。

解決策2

「String Literal Types + Union Types + Type Aliases」を使う。

解決策1の問題点は引数gradeが、

  • Bronze
  • Silver
  • Gold

以外だった場合。

// 実行結果は、NaNに
console.log(calculatePoint(130, "Diamond"));

こうなる。

仕様としてcalculatePointは引数grade

  • Bronze
  • Silver
  • Gold

のみを引数としてとることを想定している。そこで、「String Literal Types + Union Types + Type Aliases」を使う。


// String Literal Types + Union Types + Type Aliases
type Grade = 'Bronze' | 'Silver' | 'Gold';

function calculatePoint(basePoint: number, grade: Grade): number {
    // anyもいらない
    const factor = {
        'Bronze': 1.0,
        'Silver': 1.5,
        'Gold': 2.0,
    };
    return factor[grade] * basePoint;
}

次のように想定外の引数は、コンパイルエラーとして弾ける。

// コンパイルが通る
const grade: Grade = "Bronze";
console.log(calculatePoint(90, grade));
console.log(calculatePoint(100, "Gold"));
console.log(calculatePoint(120, "Silver"));
console.log(calculatePoint(130, "Bronze"));

// コンパイルエラー
// console.log(calculatePoint(130, "Diamond"));
// const anotherGrade: string = "Silver";
// console.log(calculatePoint(130, anotherGrade));

解決策3

error TS7017の数が多すぎる場合、コンパイルオプションの--suppressImplicitAnyIndexErrorsを検討する。

例えば--noImplicitAnyは導入したいけれど、

error TS7017: Element implicitly has an 'any' type because type 'XXXXX' has no index signature.

が複数箇所で多数発生してしまい、--noImplicitAnyを入れるためには相当頑張らないといけない。

そんな場合、--noImplicitAnyと共に--suppressImplicitAnyIndexErrorsを導入すれば、次のコンパイルエラーを抑制できる。

error TS7017: Element implicitly has an 'any' type because type 'XXXXX' has no index signature.

これにより一部ではあるが、--noImplicitAnyの恩恵を受けることができる。

すでにお金を生んでいて、これからも開発を続けるプロジェクトにおいて、これの価値は大きい。

余談

こんな感じでメソッド化しているとする。loadFactorsの返り値型を明示したい。

// `strict`か`noImplicitAny`が有効だとコンパイルエラーになる
function calculatePoint(basePoint: number, grade: string): number {
    const factor = loadFactors();
    return factor[grade] * basePoint;
}

// `loadFactors`の返り値型を明示したい
function loadFactors() {
    return {
        'Bronze': 1.0,
        'Silver': 1.5,
        'Gold': 2.0,
    };
}

こんな感じ。

function loadFactors(): { [G in Grade]: number } {
    return {
        'Bronze': 1.0,
        'Silver': 1.5,
        'Gold': 2.0,
    };
}

もしくはこう。

type GradeObject<T> = { [G in Grade]: T }

function loadFactors(): GradeObject<number> {
    return {
        'Bronze': 1.0,
        'Silver': 1.5,
        'Gold': 2.0,
    };
}
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
0
Help us understand the problem. What are the problem?