noImplicitAny 플래그를 사용하여 유형 스크립트를 컴파일 할 때 "객체 유형의 인덱스 서명에 암시 적으로 '모든 유형'이 있습니다"오류를 방지하려면 어떻게해야합니까?


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;
}

그러나 이렇게하면 모든 속성 유형이 인덱스 서명과 일치하도록합니다. 모든 속성이 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

안녕하세요, "anyObject [key : Object] [ 'name']"을 어떻게 처리합니까?
Code_Crash

또는 _obj = {}와 같은 것을 말하십시오. let _dbKey = _props [키] [ '이름']; _obj [_dbKey] = this [키]; 여기서 _props는 object이고 object [key]는 또한 name 속성을 갖는 객체를 반환합니다.
Code_Crash

180

오류를 피하는 또 다른 방법은 다음과 같이 캐스트를 사용하는 것입니다.

let secondValue: string = (<any>someObject)[key]; (괄호 참고)

유일한 문제는에 캐스팅 할 때 더 이상 유형 안전하지 않다는 것 any입니다. 그러나 항상 올바른 유형으로 캐스트 할 수 있습니다.

추신 : 나는 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
그러나 = 'second'+ 'Key' key로 선언하면 작동하지 않습니다.const key = (keyof ISomeObject)
실망했습니다

55

다음 tsconfig 설정 을 사용하면 이러한 오류를 무시하고 true로 설정하십시오.

suppressImplicitAnyIndexErrors

인덱스 서명이없는 개체를 인덱싱 할 때 noImplicitAny 오류를 억제하십시오.


14
그것은 당신이해서는 안되는 일입니다-아마도 당신 팀의 누군가가 코드를 더 방탄하도록이 컴파일러 옵션을 명시 적으로 설정했습니다!
atsu85

12
나는 이것이이 옵션에 대해 정확히 맞지 않다는 것을 동의한다 --noImplicitAny. 완벽하게 op의 질문을 일치시킵니다.
Ghetolay

4
@Ghetolay에 동의합니다. 인터페이스를 수정할 수없는 경우에도이 옵션 만 사용할 수 있습니다. 예를 들어와 같은 내부 인터페이스가 XMLHttpRequest있습니다.
Marco Roy

1
또한 @Ghetolay에 동의합니다. Pedro Villa Verde의 답변과 코드가 덜 추악하다는 사실을 제외하고는 이것이 질적으로 어떻게 다른지 궁금합니다. 우리는 가능한 한 문자열을 사용하여 객체 속성에 액세스하는 것을 피해야한다는 것을 알고 있지만 위험을 이해하면서 때로는 그 자유를 누리고 있습니다.
Stephen Paul

그것은 단지 절충입니다. 오류 표면적이 적고 인덱스 액세스가 엄격하거나 오류가 많은 표면적이 있고 알 수없는 인덱스에 쉽게 액세스 할 수 있습니다. TS2.1 keyof운영자는 모든 것을 엄격하게 유지할 수 있습니다. Piotr의 답변을 참조하십시오!
trusktr

24

위에서 언급 한 'keyof'솔루션이 작동합니다. 그러나 변수가 한 번만 사용되는 경우 (예 : 객체를 통한 반복 등)에는 유형 변환 할 수도 있습니다.

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

감사. 다른 객체의 키를 반복 할 때 임의의 키 액세스에 작동합니다.
bucabay 2014 년

19

사용하다 keyof typeof

const cat = {
    name: 'tuntun'
}

const key: string = 'name' 

cat[key as keyof typeof cat]

7

@Piotr Lewandowski의 답변과 비슷하지만 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 };

어딘가에서 문자열 속성으로 사용하는 경우 일반적으로 이것이 유효하다는 것을 알고 있기 때문에 일반적으로 이것이 필요하지 않습니다.

이 방법은 인덱서에 액세스해야하는 코드가 많고 입력을 한 곳에서 변경할 수있는 경우에 특히 유용합니다.

참고 : 나는 strict모드를 사용 하고 unknown있으며 반드시 필요합니다.

컴파일 된 코드는 단지 indexer = this이므로 typescript가 생성 할 때와 매우 유사 _this = this합니다.


1
경우에 따라 Record<T>유형을 대신 사용할 수있는 경우도 있습니다. 지금은 세부적인 내용을 조사 할 수는 없지만 일부 경우에는 더 잘 작동 할 수 있습니다.
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

키가 문자열이고 값을 입력 할 수있는 유형을 선언하면이 유형으로 객체를 선언하면 보풀이 나타나지 않습니다.

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.