TypeScript 팀은 6.0 릴리스에서 새로운 컴파일러 플래그인 --noPropertyAccessFromIndexSignature를 출시했습니다. 이 플래그를 활성화하면 컴파일러는 인덱스 시그니처에서 오는 속성에 대한 점 표기법(dot-notation) 접근을 거부하며, 개발자가 대괄호 표기법(bracket notation)을 사용하도록 강제하여 잠재적인 undefined 값을 프로덕션이 아닌 컴파일 타임에 드러나게 합니다.

이 플래그가 중요한 이유

JavaScript에서 객체는 종종 딕셔너리 역할을 하며, TypeScript는 Record<string, T>와 같은 인덱스 시그니처를 통해 이러한 구조를 타입화할 수 있게 해줍니다. 언어 차원에서는 obj.keyobj["key"]를 동일하게 취급하므로, 컴파일러는 키를 런타임에만 알 수 있는 경우에도 해당 속성이 존재한다고 가정합니다. 이러한 암묵적인 가정은 많은 크래시의 원인이 됩니다. obj.missingProp에 접근하는 코드는 컴파일도 잘 되고 실행도 되지만, 값이 undefined이기 때문에 결국 오류를 던지게 됩니다.

점 표기법은 암묵적인 보증을 수반합니다. 즉, 읽는 사람과 타입 체커에게 해당 속성이 확실히 존재한다는 것을 알려줍니다. 반면 대괄호 표기법은 불확실성을 나타냅니다. 키가 없을 수도 있고, 결과가 undefined일 수 있음을 시사합니다. --noPropertyAccessFromIndexSignature는 이러한 시각적, 의미적 구분을 강제하여, 런타임 에러의 한 종류를 컴파일 타임 진단으로 전환합니다.

플래그 작동 방식

플래그를 켜면 인덱스 시그니처를 통해 점 표기법으로 속성에 접근하는 모든 표현식은 에러로 표시됩니다. 코드는 대괄호를 사용하도록 재작성해야 합니다.

// Before
const name = userData.name;          // OK even if "name" is not in the index

// After enabling the flag
const name = userData["name"];       // Error unless brackets are used

그런 다음 컴파일러는 이미 대괄호 접근에 사용하고 있는 것과 동일한 undefined 처리 규칙을 적용합니다. 만약 --noUncheckedIndexedAccess도 활성화되어 있다면, userData["name"]의 타입은 T | undefined가 되어 개발자가 누락된 경우를 반드시 확인하도록 강제합니다.

실질적인 마이그레이션 단계

  1. tsconfig.json에서 플래그 활성화:

    {
      "compilerOptions": {
        "noPropertyAccessFromIndexSignature": true
      }
    }
    
  2. 타입 체커 실행. 인덱스 시그니처 키에 대한 모든 점 표기법 접근이 에러로 나타납니다.

  3. 점을 대괄호로 교체. 이 변경은 기계적인 작업이며 런타임 성능에는 영향을 미치지 않습니다.

  4. 결과로 발생하는 undefined 타입 처리. 필요한 경우 널 병합 연산자(nullish coalescing), 옵셔널 체이닝(optional chaining) 또는 명시적인 체크를 추가합니다.

  5. 가장 강력한 안전망을 위해 --noUncheckedIndexedAccess와 함께 사용하는 것을 고려하십시오. 두 플래그를 함께 사용하면 모든 딕셔너리 스타일의 접근이 잠재적으로 누락될 수 있는 것으로 처리됩니다.

명시적 속성을 유지해야 하는 경우

필드가 안정적인 API 계약의 일부라면, 인덱스 시그니처에 의존하기보다 명시적인 속성으로 선언하십시오. 명시적 속성은 점 표기법을 계속 허용하며, (타입 시스템이 검증할 수 있는 한) 해당 필드가 항상 존재한다는 보증을 유지합니다. 인덱스 시그니처는 키를 미리 알 수 없는 진정으로 동적인 데이터에 대해서만 사용하십시오.

반론: 증가하는 번거로움

일부 팀은 특히 유연한 객체를 많이 사용하는 코드베이스에서 추가된 대괄호가 번거롭다고 느낄 수 있습니다. 이 플래그는 엄격한 규율을 강제하며, 레거시 프로젝트의 경우 상당한 규모의 리팩터링이 필요할 수 있습니다. 이러한 경우에는 플래그를 점진적으로 도입하여, 우선 새로운 모듈에만 제한적으로 적용하면서 전체 코드베이스가 시간이 지남에 따라 이 패턴을 채택하도록 할 수 있습니다.

향후 주목할 점

이 플래그는 더 엄격한 타입 안전성을 향한 TypeScript 6.0의 광범위한 움직임의 일부입니다. 향후 릴리스에서는 객체 스프레드(object spread), 옵셔널 체이닝 또는 추론된 any 사용에 대한 추가적인 체크가 도입될 수 있습니다. TypeScript 로드맵을 주시하면 팀이 배포 일정을 방해하지 않으면서 다음 안전 기능 세트를 언제 도입할지 결정하는 데 도움이 될 것입니다.

요약: --noPropertyAccessFromIndexSignature를 활성화하면 "이 속성은 보장됨"과 "이 속성은 누락될 수 있음" 사이의 구분이 코드에서 명확해지며, 프로덕션에 도달하기 전에 한 종류의 버그를 통째로 잡아낼 수 있습니다. 조용히 발생하던 런타임 실패를 컴파일 타임 에러로 바꾸는 것은 신뢰성에 비례하여 매우 큰 영향을 미치는 작은 변화입니다.