blog
TypeScript에서 빈 배열의 0번째 요소에 접근하면 에러가 날까?
Front-end / TypeScript#TypeScript#noUncheckedIndexedAccess#배열#tsconfig
결론: 컴파일 에러도, 런타임 에러도 나지 않는다. 런타임에서는 undefined가 나오는데, 기본 설정의 TypeScript는 이것을 알려주지 않는다.
런타임 (JavaScript)
존재하지 않는 인덱스에 접근하면 에러가 아니라 undefined를 반환한다.
const arr: number[] = [];
console.log(arr[0]); // undefined
컴파일 타임 (TypeScript 기본 설정)
const arr: number[] = [];
const first = arr[0]; // 타입: number (undefined가 빠져 있음!)
first.toFixed(2); // 컴파일 통과 → 런타임 TypeError
기본 설정에서 number[]의 인덱스 접근 결과는 number로 추론된다. 실제 값은 undefined인데 타입은 number라서, 이후 코드에서 런타임 에러가 날 수 있다.
noUncheckedIndexedAccess
tsconfig.json에서 이 옵션을 켜면 인덱스 접근 결과에 undefined가 포함된다.
{
"compilerOptions": {
"noUncheckedIndexedAccess": true
}
}
const arr: number[] = [];
const first = arr[0]; // 타입: number | undefined
first.toFixed(2); // ❌ 'first' is possibly 'undefined'
first?.toFixed(2); // ✅
Record<string, T> 같은 인덱스 시그니처 접근에도 똑같이 적용된다. strict에는 포함되지 않으므로 따로 켜야 한다. 안전성이 크게 올라가는 대신 arr[i]마다 확인이 필요해지므로, 반복문 안에서는 for...of나 forEach처럼 인덱스를 쓰지 않는 순회를 쓰면 편하다.
안전하게 접근하는 방법
// 1. 기본값 지정
const first = arr[0] ?? 0;
// 2. at(): 옵션과 관계없이 항상 T | undefined로 추론됨
const last = arr.at(-1);
// 3. 길이 확인 후 접근
if (arr.length > 0) {
const first = arr[0];
}
// 4. 구조 분해
const [head] = arr; // 기본 설정에서는 number, 옵션을 켜면 number | undefined
길이를 확인해도 noUncheckedIndexedAccess를 켠 상태에서는 TypeScript가 arr[0]을 여전히 number | undefined로 본다. 길이 검사로는 타입이 좁혀지지 않기 때문이다. 이때는 const first = arr[0]; if (first !== undefined) { ... }처럼 값 자체를 검사한다.