Ch 02. 타입 에러 메시지 해석법
TypeScript 에러 메시지는 처음에는 낯설고 장황합니다. 빨간 밑줄과 함께 터미널을 가득 채우는 영어 문장들을 보면 막막해지죠. 하지만 구조를 알고 나면 에러 메시지가 오히려 "어디를 어떻게 고쳐야 하는지"를 알려주는 안내서라는 것을 알게 됩니다.
에러 메시지의 구조
TypeScript 에러는 보통 세 부분으로 이루어집니다.
에러 코드 위치 메시지
↓ ↓ ↓
TS2345 src/app.ts:12:5 Argument of type 'string' is not assignable
to parameter of type 'number'.
에러 코드(TS로 시작하는 숫자)를 검색하면 공식 문서와 해결 예제를 바로 찾을 수 있습니다. 자주 만나는 에러 코드 10가지를 살펴봅니다.
에러 1. TS2345 — 타입 불일치
가장 흔하게 만나는 에러입니다. 함수에 잘못된 타입의 인수를 전달할 때 발생합니다.
Argument of type 'string' is not assignable to parameter of type 'number'.
// 파일: src/errors/ts2345.tsfunction add(a: number, b: number): number { return a + b;}// 에러 발생add("1", 2);// Argument of type 'string' is not assignable to parameter of type 'number'.// 해결 방법 1: 인수 타입 수정add(1, 2);// 해결 방법 2: 함수 시그니처 수정 (의도적으로 문자열도 받으려면)function addFlexible(a: number | string, b: number): number { return Number(a) + b;}
에러 2. TS2339 — 존재하지 않는 프로퍼티
Property 'email' does not exist on type 'User'.
// 파일: src/errors/ts2339.tsinterface User { id: number; name: string;}const user: User = { id: 1, name: "Alice" };// 에러 발생console.log(user.email);// Property 'email' does not exist on type 'User'.// 해결 방법 1: 타입에 프로퍼티 추가interface UserWithEmail { id: number; name: string; email: string;}// 해결 방법 2: 선택적 프로퍼티interface UserOptionalEmail { id: number; name: string; email?: string;}const u2: UserOptionalEmail = { id: 1, name: "Alice" };if (u2.email) { console.log(u2.email); // 여기서는 string으로 좁혀짐}
에러 3. TS2322 — 할당 불가
Type 'string | undefined' is not assignable to type 'string'.
Type 'undefined' is not assignable to type 'string'.
// 파일: src/errors/ts2322.tsfunction getName(): string | undefined { return Math.random() > 0.5 ? "Alice" : undefined;}const name: string = getName(); // 에러 발생// 해결 방법 1: 기본값 제공const name1: string = getName() ?? "기본값";// 해결 방법 2: 변수 타입 완화const name2: string | undefined = getName();// 해결 방법 3: 단언 (undefined가 절대 아님을 확신할 때)const name3: string = getName()!; // non-null assertion
에러 4. TS2532 — 객체가 undefined일 수 있음
Object is possibly 'undefined'.
// 파일: src/errors/ts2532.tsconst users = [{ id: 1, name: "Alice" }, { id: 2, name: "Bob" }];// 에러 발생 (noUncheckedIndexedAccess 활성화 시)const first = users[0];console.log(first.name); // Object is possibly 'undefined'.// 해결 방법 1: 옵셔널 체이닝console.log(users[0]?.name);// 해결 방법 2: 명시적 검사if (users[0]) { console.log(users[0].name);}// 해결 방법 3: 기본값const firstName = users[0]?.name ?? "알 수 없음";
에러 5. TS2551 — 오타가 있는 프로퍼티
Property 'lenght' does not exist on type 'string'. Did you mean 'length'?
TypeScript는 오타를 감지하고 올바른 이름을 제안합니다. "Did you mean...?" 메시지가 보이면 그냥 제안을 따르면 됩니다.
// 파일: src/errors/ts2551.tsconst message = "Hello, World!";// 에러 발생console.log(message.lenght); // Did you mean 'length'?// 해결 방법console.log(message.length);
에러 6. TS7006 — 암묵적 any 매개변수
Parameter 'event' implicitly has an 'any' type.
// 파일: src/errors/ts7006.ts// noImplicitAny: true 환경에서 에러 발생function handleClick(event) { // 에러 console.log(event.target);}// 해결 방법: 매개변수 타입 명시function handleClickSafe(event: MouseEvent) { console.log(event.target);}// 또는 이벤트 타입을 모를 때function handleClickUnknown(event: Event) { if (event.target instanceof HTMLButtonElement) { console.log(event.target.textContent); }}
에러 7. TS2554 — 인수 개수 불일치
Expected 2 arguments, but got 1.
// 파일: src/errors/ts2554.tsfunction createPoint(x: number, y: number): { x: number; y: number } { return { x, y };}// 에러 발생const point = createPoint(1); // Expected 2 arguments, but got 1.// 해결 방법 1: 누락된 인수 추가const point1 = createPoint(1, 0);// 해결 방법 2: 기본값으로 선택적 매개변수 만들기function createPointWithDefault(x: number, y: number = 0) { return { x, y };}const point2 = createPointWithDefault(1); // 정상
에러 8. TS2769 — 오버로드 불일치
No overload matches this call.
Overload 1 of 2, '(value: string): string', gave the following error.
Overload 2 of 2, '(value: number): number', gave the following error.
// 파일: src/errors/ts2769.tsfunction double(value: string): string;function double(value: number): number;function double(value: string | number): string | number { if (typeof value === "string") return value.repeat(2); return value * 2;}// 에러 발생double(true); // No overload matches this call.// 해결 방법: 지원하는 타입만 전달double("hello"); // "hellohello"double(5); // 10// 또는 오버로드에 boolean 추가function doubleExtended(value: string): string;function doubleExtended(value: number): number;function doubleExtended(value: boolean): boolean;function doubleExtended(value: string | number | boolean): string | number | boolean { if (typeof value === "string") return value.repeat(2); if (typeof value === "number") return value * 2; return !value;}
에러 9. TS2352 — 타입 단언 불가
Conversion of type 'string' to type 'number' may be a mistake because neither type
sufficiently overlaps with the other.
// 파일: src/errors/ts2352.tsconst value = "123";// 에러 발생const num = value as number;// Conversion of type 'string' to type 'number' may be a mistake...// 해결 방법 1: 올바른 변환 함수 사용const num1 = Number(value);const num2 = parseInt(value, 10);// 해결 방법 2: 정말로 단언이 필요하다면 (드물게)const num3 = value as unknown as number; // "나는 확신한다"는 명시적 표현
에러 10. TS2366 — 반환값 누락 (switch 완전성 검사)
Function lacks ending return statement and return type does not include 'undefined'.
// 파일: src/errors/ts2366.tstype Shape = "circle" | "square" | "triangle";function getArea(shape: Shape, size: number): number { switch (shape) { case "circle": return Math.PI * size ** 2; case "square": return size ** 2; // triangle 빠짐 → 에러 발생 }}// 해결 방법 1: 누락된 케이스 추가function getAreaFixed(shape: Shape, size: number): number { switch (shape) { case "circle": return Math.PI * size ** 2; case "square": return size ** 2; case "triangle": return (Math.sqrt(3) / 4) * size ** 2; }}// 해결 방법 2: never로 완전성 강제function assertNever(value: never): never { throw new Error(`처리되지 않은 케이스: ${String(value)}`);}function getAreaStrict(shape: Shape, size: number): number { switch (shape) { case "circle": return Math.PI * size ** 2; case "square": return size ** 2; case "triangle": return (Math.sqrt(3) / 4) * size ** 2; default: return assertNever(shape); // triangle 추가 후 여기 도달하면 컴파일 에러 }}
에러 메시지 읽기 연습
복잡한 에러일수록 메시지를 아래에서 위로 읽는 것이 효과적입니다. 가장 아래의 구체적인 에러가 근본 원인이고, 위로 올라갈수록 그 에러가 전파된 경로입니다.
Type '{ id: number; name: string; }' is not assignable to type 'User'.
Property 'email' is missing in type '{ id: number; name: string; }'
but required in type 'User'.
이 메시지는 아래서부터 읽습니다. "User 타입에는 email이 필수인데, 지금 넘기는 객체에는 없다." 원인은 명확합니다. email을 추가하거나 User 타입에서 email을 선택적으로 만들면 됩니다.
에러 메시지는 적이 아닙니다. TypeScript 컴파일러가 우리 대신 버그를 찾아준 것입니다. 메시지를 읽는 연습을 하면 할수록 에러를 고치는 속도가 빨라집니다.