[typescript] 에러 분석

Element implicitly has an 'any' type because expression of type 'string' can't be used to index

참고 TypeScript에서 string key로 객체에 접근하기

TypeScript는 기본적으로 객체의 프로퍼티를 읽을 때, string타입의 key 사용을 허용하지 않는다. string literal 타입만 허용되는 곳에 string 타입을 사용했기 때문

interface Vector3D {
  x: number;
  y: number;
  z: number;
}

const calculateLengthL1 = (v: Vector3D): number => {
  let length = 0;

  for (const axis of Object.keys(v)) {
    /**
     * <error message>
     * 'string'은 'Vector3D'의 인덱스로 사용할 수 없기에 엘리먼트는 암시적으로 'any' 타입입니다.
     * Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'Vector3D'.
     * No index signature with a parameter of type 'string' was found on type 'Vector3D'.
     */
    const coord = v[axis];
    length += Math.abs(coord);
  }

  return length;
}

string과 string literal

a 변수는 let으로 선언되어 재할당될 수 있을 경우 어떤 문자열이든 넣을 수 있으며 그 경우의 수가 무한대이다. 그렇기 때문에 컴파일러는 이 변수를 string 타입으로 추론

b 변수는 명시적으로 string 타입으로 선언했으므로 그냥 string 타입.

c 변수string literal 타입. "Hello World"만을 허용하는 타입을 선언 한 것 컴파일러는 이 변수를 string이 아닌 조금 더 좁은 타입(narrowed type)으로 선언한 것으로 추론한다. 이 것을 Literal Narrowing이라고 한다.

let a = "Hello World"
const b: string = "Hello World"
const c = "Hello World"

아래와 같이 명시적으로 literal type을 선언하면 let으로 선언된 변수도 "Hellow World" 타입만을 허용하도록 만들 수도 있다.

type HelloWorldType = "Hello World" // literal type

let a: HelloWorldType = "Hello World" // ok
a = "hahaha" // compile error: "hahaha"는 "Hello World"가 아니기 때문.

해결방법

Index Signature를 선언한다. 위의 에러 메시지 중 No index signature with a parameter of type 'string' was found on type 'Vector3D'. 라는 메시지가 있었다.

interface Vector3D {
  [index: string]: any;
  x: number;
  y: number;
  z: number;
}

const calculateLengthL1 = (v: Vector3D): number => {
  let length = 0;

  for (const axis of Object.keys(v)) {
    const coord = v[axis];
    length += Math.abs(coord);
  }

  return length;
}

또는 아래와 같이 해결 가능

interface Vector3D {
  x: number;
  y: number;
  z: number;
}

const calculateLengthL1 = (v: Vector3D): number => {
  let length = 0;

  for (const axis of Object.keys(v)) {
-     const coord = v[axis];
+     const coord = v[axis as keyof Vector3D];
//    또는
+     const coord = v[axis as keyof typeof v];
    length += Math.abs(coord);
  }

  return length;
}

links

social