0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Posted at

コンパイラオプション--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,
    };
}
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?