Giting.
낮의 Giting
홈 › 스킬 › type-menu
타입스크립트 에러 사전 실물 캡처 사전 15항목 · 자체 제작
◆ 도입 후보

네이버 fe-news 80호를 교차 스캔했더니 react-typescript-cheatsheet가 5회로 최다 반복, 프런트엔드 최대 고통이 TS 타입이라는 게 실측으로 나왔다. 그래서 css-menu 계보의 증상 사전 포맷으로 TS 에러 사전을 만들었다. 항목의 에러 메시지는 지어낸 게 아니라 실제 tsc --strict 를 돌려 확보한 원문 13종(TS18048·TS7006·TS2322 등)이 근거다. 핵심 규율은 'any·! 로 덮지 않는다'다. 타입 에러를 없애는 쉬운 길은 any 캐스팅이지만 그건 런타임 버그를 남긴다. 이 사전은 좁히기로 제대로 고치고, non-null !·리터럴 타입·floating promise처럼 상황에 따라 답이 갈리는 건 분기형으로 진단부터 시킨다. AI로 TS 코드를 짜다 빨간 줄에 막히는 사람에게 도입 후보.

실물부터, 설치 전에 전부 만져보세요

아래는 이미지가 아니라 이 스킬이 담고 있는 진짜 HTML입니다. 눌러 보세요.
타입스크립트 에러 사전 · 15가지

빨간 줄 영어 메시지를
사람 말로 옮겨요

TS 에러 메시지는 영어에 코드번호(TS18048…)라 초보에겐 암호다. 이 사전은 그 메시지를 사람 말로 옮기고, any로 덮지 않고 제대로 고치는 요청 문장 + before/after를 준다. 전부 실제 tsc가 뱉은 원문 기준.

TS18048'u.email' is possibly 'undefined'.
"'possibly undefined' 라고 빨간 줄이 떠요"옵셔널 체이닝(?.) + 기본값(??), 또는 앞에서 가드로 좁힌다. any 로 덮지 않는다.
TS7006Parameter 'items' implicitly has an 'any' type.
"'implicitly has any type' 라고 떠요"매개변수에 타입을 적어준다. 모르면 최소한 구조를 적는다.
TS2322Type 'string' is not assignable to type 'number'.
"'Type X is not assignable to type Y' 라고 떠요"값을 올바른 타입으로 바꾸거나, 타입 선언을 실제 값에 맞춘다. 둘 중 뭐가 맞는지 먼저 본다.

이 값이 undefined일 수 있어서 나는 TS18048 에러야. any로 막지 말고, 옵셔널 체이닝이나 기본값으로 안전하게 좁혀서 고쳐줘.

덮지 않고 고치기

any로 막지 말고
좁혀서 고쳐요

옵셔널 체이닝(?.) + 기본값(??), 또는 앞에서 가드로 좁힌다. any 로 덮지 않는다. 빨간 줄이 사라지고 undefined일 때 앱이 안 터지면 성공.

이 값이 undefined일 수 있어서 나는 TS18048 에러야. any로 막지 말고, 옵셔널 체이닝이나 기본값으로 안전하게 좁혀서 고쳐줘.

$ tscerror TS18048: 'u.email' is possibly 'undefined'.
✗ 에러 나는 코드
function f(u: User) {
  return u.email.toLowerCase();
  //     ~~~~~~~ possibly undefined
}
✓ 제대로 고침
function f(u: User) {
  return u.email?.toLowerCase() ?? "";
}
AI한테 시키는 공식

원문 그대로 붙이면
코드번호로 찾아요

빨간 줄 원문 그대로사전에서 코드번호/증상 찾기고치는 문장 복사
✕

타입 에러 나는데 그냥 any로 막아줘

○

이 값이 undefined일 수 있어서 나는 에러야. 옵셔널 체이닝이나 기본값으로 좁혀서 고쳐줘

코드번호 찾기

이 번호가 뜨면
이 뜻이에요

왼쪽이 터미널에 뜨는 번호, 오른쪽이 사람 말이에요.

Claude Code 스킬

에러를 붙이면
AI가 사전을 펴요

스킬로 깔아 두면 빨간 줄 원문만 붙여도 any 없이 고치는 문장으로 바꿔요.

/plugin marketplace add hanmariyang/giting-skills

/plugin install type-menu@giting

GitHub에서 오픈소스 보기 ↗

01 undefined·null일 수 있음 3

즉방형

"'possibly undefined' 라고 빨간 줄이 떠요"

TS18048
$ tsc  error TS18048: 'u.email' is possibly 'undefined'.
✗ 에러 나는 코드
function f(u: User) {
  return u.email.toLowerCase();
  //     ~~~~~~~ possibly undefined
}
✓ 제대로 고침 (any·! 로 덮지 않음)
function f(u: User) {
  return u.email?.toLowerCase() ?? "";
}
처방: 옵셔널 체이닝(?.) + 기본값(??), 또는 앞에서 가드로 좁힌다. any 로 덮지 않는다. 빨간 줄이 사라지고 undefined일 때 앱이 안 터지면 성공.
즉방형

"find/pop 결과에서 undefined 에러가 나요"

TS18048
$ tsc  error TS18048: 'x' is possibly 'undefined'.
✗ 에러 나는 코드
const x = arr.find(n => n > 0);
return x + 1;  // x 가 undefined 일 수 있음
✓ 제대로 고침 (any·! 로 덮지 않음)
const x = arr.find(n => n > 0);
if (x === undefined) return 0;
return x + 1;
처방: 찾은 결과를 if 로 좁히거나, 없을 때 처리를 명시한다. 못 찾은 경우가 처리돼 있고 빨간 줄이 없으면 성공.
분기형

"느낌표(!)를 붙이라고 해서 붙였는데 찜찜해요"

TS2531
$ tsc  error TS2531: Object is possibly 'null'.
✗ 에러 나는 코드
const el = document.querySelector('.x')!;
el.textContent = 'hi';  // 없으면 런타임 터짐
✓ 제대로 고침 (any·! 로 덮지 않음)
const el = document.querySelector('.x');
if (el) el.textContent = 'hi';
갈림길: 정말 절대 null이 아님이 보장됨(직전에 체크 등) / 그냥 빨간 줄 없애려고 붙였다 ! 가 남았다면 왜 안전한지 설명이 있고, 아니면 가드로 바뀌었으면 성공.
증상코드유형이렇게 말해도AI에게 이렇게
"'possibly undefined' 라고 빨간 줄이 떠요" TS18048 즉방형 "옵셔널 속성 썼더니 에러" · "u.email 에서 빨간 줄" · "있을 수도 없을 수도 있는 값" 이 값이 undefined일 수 있어서 나는 TS18048 에러야. any로 막지 말고, 옵셔널 체이닝이나 기본값으로 안전하게 좁혀서 고쳐줘.
"find/pop 결과에서 undefined 에러가 나요" TS18048 즉방형 "배열에서 찾은 값이 undefined" · "find 결과 못 씀" · "있을지 없을지 모르는 항목" find 결과가 undefined일 수 있어서 TS18048이 나. 찾은 값을 if로 좁히거나 없을 때를 처리해서 고쳐줘.
"느낌표(!)를 붙이라고 해서 붙였는데 찜찜해요" TS2531 분기형 "non-null assertion" · "! 붙이면 되긴 하는데" · "value! 로 막기" 여기 ! 를 붙여서 에러를 막았는데, 정말 null이 아님이 보장되는지 아니면 그냥 덮은 건지 판단해서, 후자면 제대로 좁혀줘.

02 타입을 몰라서 any 2

즉방형

"'implicitly has any type' 라고 떠요"

TS7006
$ tsc  error TS7006: Parameter 'items' implicitly has an 'any' type.
✗ 에러 나는 코드
function f(items) {
  return items.map(i => i.id);
}
✓ 제대로 고침 (any·! 로 덮지 않음)
function f(items: { id: string }[]) {
  return items.map(i => i.id);
}
처방: 매개변수에 타입을 적어준다. 모르면 최소한 구조를 적는다. 매개변수에 타입이 붙고 빨간 줄이 없으면 성공.
즉방형

"'this implicitly has type any' 라고 떠요"

TS2683
$ tsc  error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation.
✗ 에러 나는 코드
class C {
  v = 1;
  m() { return function() { return this.v; }; }
}
✓ 제대로 고침 (any·! 로 덮지 않음)
class C {
  v = 1;
  m() { return () => this.v; }
}
처방: 화살표 함수(this 를 바깥에서 물려받음)로 바꾸거나 this 타입을 명시한다. this 가 의도한 객체를 가리키고 빨간 줄이 없으면 성공.
증상코드유형이렇게 말해도AI에게 이렇게
"'implicitly has any type' 라고 떠요" TS7006 즉방형 "매개변수에 빨간 줄" · "타입 안 적었더니 에러" · "함수 인자 any" 이 함수 매개변수에 타입이 없어서 TS7006이 나. any로 두지 말고 실제 들어오는 값에 맞는 타입을 적어줘.
"'this implicitly has type any' 라고 떠요" TS2683 즉방형 "this 에서 에러" · "콜백 안에서 this" · "함수 안 this any" 이 함수 안 this 가 TS2683으로 막혀. 화살표 함수로 바꿔서 바깥 this 를 쓰게 고쳐줘.

03 타입이 안 맞음 3

즉방형

"'Type X is not assignable to type Y' 라고 떠요"

TS2322
$ tsc  error TS2322: Type 'string' is not assignable to type 'number'.
✗ 에러 나는 코드
const n: number = "3";  // 문자열을 숫자 자리에
✓ 제대로 고침 (any·! 로 덮지 않음)
const n: number = 3;
// 문자열이 맞다면: const n = "3";
처방: 값을 올바른 타입으로 바꾸거나, 타입 선언을 실제 값에 맞춘다. 둘 중 뭐가 맞는지 먼저 본다. 타입과 값이 일치하고 빨간 줄이 없으면 성공.
즉방형

"'Expected N arguments, but got M' 이 떠요"

TS2554
$ tsc  error TS2554: Expected 2 arguments, but got 1.
✗ 에러 나는 코드
function add(a: number, b: number) { return a + b; }
add(1);  // b 빠짐
✓ 제대로 고침 (any·! 로 덮지 않음)
add(1, 2);
// b 가 선택이라면: function add(a: number, b = 0)
처방: 빠진 인자를 채우거나, 그 인자를 옵셔널(?)로 만들지 결정한다. 함수 호출의 인자 수가 맞고 빨간 줄이 없으면 성공.
즉방형

"콜백 넘겼는데 타입이 안 맞는대요"

TS2322
$ tsc  error TS2322: Type '(x: string) => void' is not assignable to type '(x: number) => void'.
✗ 에러 나는 코드
const fn: (x: number) => void = (x: string) => {};
✓ 제대로 고침 (any·! 로 덮지 않음)
const fn: (x: number) => void = (x) => {};
처방: 콜백 매개변수 타입을 기대 타입에 맞춘다(대개 그냥 지우면 추론된다). 콜백이 올바른 타입으로 호출되고 빨간 줄이 없으면 성공.
증상코드유형이렇게 말해도AI에게 이렇게
"'Type X is not assignable to type Y' 라고 떠요" TS2322 즉방형 "타입이 안 맞는대요" · "문자열을 숫자에 넣음" · "assignable 에러" TS2322 타입 불일치가 나. 값이 잘못된 건지 타입 선언이 잘못된 건지 판단해서 맞는 쪽으로 고쳐줘.
"'Expected N arguments, but got M' 이 떠요" TS2554 즉방형 "인자 개수가 안 맞음" · "함수 부를 때 빨간 줄" · "매개변수 빠뜨림" TS2554 인자 개수 에러가 나. 빠진 인자를 채울지, 그 매개변수를 옵셔널로 만들지 판단해서 고쳐줘.
"콜백 넘겼는데 타입이 안 맞는대요" TS2322 즉방형 "함수 타입 불일치" · "핸들러 타입 에러" · "콜백 매개변수 에러" 콜백 타입이 TS2322로 안 맞아. 매개변수 타입을 기대하는 함수 타입에 맞추거나, 추론되게 타입을 지워서 고쳐줘.

04 속성·모양이 안 맞음 3

즉방형

"'Property X does not exist' 라고 떠요"

TS2339
$ tsc  error TS2339: Property 'b' does not exist on type '{ a: number; }'.
✗ 에러 나는 코드
const o = { a: 1 };
console.log(o.b);  // b 없음
✓ 제대로 고침 (any·! 로 덮지 않음)
const o = { a: 1, b: 2 };
console.log(o.b);
처방: 오타면 고치고, 실제 있는 속성이면 타입 정의에 추가한다. 접근한 속성이 타입에 있고 빨간 줄이 없으면 성공.
즉방형

"'Object literal may only specify known properties' 가 떠요"

TS2353
$ tsc  error TS2353: Object literal may only specify known properties, and 'b' does not exist in type 'Opt'.
✗ 에러 나는 코드
interface Opt { a: number }
const opt: Opt = { a: 1, b: 2 };
✓ 제대로 고침 (any·! 로 덮지 않음)
interface Opt { a: number; b: number }
const opt: Opt = { a: 1, b: 2 };
처방: 오타면 고치고, 필요한 속성이면 타입에 추가한다. 객체의 속성이 타입과 일치하면 성공.
즉방형

"readonly 배열을 못 바꾸겠어요"

TS2339
$ tsc  error TS2339: Property 'push' does not exist on type 'readonly number[]'.
✗ 에러 나는 코드
const arr: readonly number[] = [1, 2];
arr.push(3);
✓ 제대로 고침 (any·! 로 덮지 않음)
const arr: readonly number[] = [1, 2];
const next = [...arr, 3];
처방: 새 배열을 만들어 반환한다(불변). 정말 바꿔야 하면 readonly 를 뗀다. 원본을 안 건드리고 새 배열이 나오면 성공.
증상코드유형이렇게 말해도AI에게 이렇게
"'Property X does not exist' 라고 떠요" TS2339 즉방형 "없는 속성 접근" · "o.b 에서 빨간 줄" · "오타난 속성명" TS2339 없는 속성 에러가 나. 오타인지 타입 정의에서 빠진 건지 판단해서 고쳐줘.
"'Object literal may only specify known properties' 가 떠요" TS2353 즉방형 "객체에 속성 더 넣었더니 에러" · "초과 속성" · "props 오타" TS2353 초과 속성 에러야. 그 속성이 오타인지 타입에 추가해야 하는 건지 보고 고쳐줘.
"readonly 배열을 못 바꾸겠어요" TS2339 즉방형 "push 가 안 됨" · "읽기 전용 배열" · "readonly 수정 에러" readonly 배열을 바꾸려다 에러가 나. 원본 수정 대신 새 배열을 만들어 반환하는 식으로 고쳐줘.

05 좁히기·유니온 2

즉방형

"유니온 타입에서 메서드를 못 써요"

TS2339
$ tsc  error TS2339: Property 'toUpperCase' does not exist on type 'string | number'.
✗ 에러 나는 코드
function f(x: string | number) {
  return x.toUpperCase();
}
✓ 제대로 고침 (any·! 로 덮지 않음)
function f(x: string | number) {
  return typeof x === "string" ? x.toUpperCase() : String(x);
}
처방: typeof 로 좁힌 뒤 쓴다. 각 타입별로 분기돼 있고 빨간 줄이 없으면 성공.
분기형

"'up'을 넣었는데 string이라 안 받아줘요"

TS2345
$ tsc  error TS2345: Argument of type 'string' is not assignable to parameter of type '"up" | "down"'.
✗ 에러 나는 코드
function move(dir: "up" | "down") {}
const d = "up";
move(d);  // d 는 string 으로 추론
✓ 제대로 고침 (any·! 로 덮지 않음)
const d = "up" as const;
move(d);
갈림길: 그 값이 고정 상수(안 바뀜) / 값이 런타임에 바뀔 수 있음 값이 요구 타입으로 좁혀지고 빨간 줄이 없으면 성공.
증상코드유형이렇게 말해도AI에게 이렇게
"유니온 타입에서 메서드를 못 써요" TS2339 즉방형 "string | number 에서 에러" · "toUpperCase 안 됨" · "둘 중 하나인데 메서드 못 씀" string | number 유니온에서 toUpperCase가 TS2339로 막혀. typeof로 문자열인지 좁힌 뒤 쓰게 고쳐줘.
"'up'을 넣었는데 string이라 안 받아줘요" TS2345 분기형 "리터럴 타입 안 맞음" · "as const 필요" · "좁은 타입 요구" 리터럴 타입 에러(TS2345)가 나. 이 값이 고정 상수인지 바뀔 수 있는지 보고, 전자면 as const, 후자면 검증으로 고쳐줘.

06 async·Promise 2

즉방형

"async 함수 결과가 Promise라고 떠요"

TS2322
$ tsc  error TS2322: Type 'Promise<number>' is not assignable to type 'number'.
✗ 에러 나는 코드
async function g(): Promise<number> { return 1; }
function use() {
  const n: number = g();  // await 빠짐
}
✓ 제대로 고침 (any·! 로 덮지 않음)
async function g(): Promise<number> { return 1; }
async function use() {
  const n: number = await g();
}
처방: await 를 붙인다(그 함수도 async 여야 함). await가 붙고 실제 값이 나오면 성공.
분기형

"await 안 붙였다고 경고가 떠요"

floating-promise
$ tsc  Promises must be awaited, end with a call to .catch, or be marked void.
✗ 에러 나는 코드
function save() { api.post(data); }  // 실패해도 모름
✓ 제대로 고침 (any·! 로 덮지 않음)
async function save() { await api.post(data); }
갈림길: 결과·완료를 기다려야 함 / 정말 기다릴 필요 없는 fire-and-forget 기다려야 할 건 await되고, 아닌 건 의도가 명시되면 성공.
증상코드유형이렇게 말해도AI에게 이렇게
"async 함수 결과가 Promise라고 떠요" TS2322 즉방형 "await 빠뜨림" · "Promise 가 숫자에 안 들어감" · "비동기 결과 타입 에러" async 함수 결과가 Promise라 TS2322가 나. await를 붙이고 감싸는 함수도 async로 만들어서 고쳐줘.
"await 안 붙였다고 경고가 떠요" floating-promise 분기형 "promise 를 안 기다림" · "async 호출 경고" · "no-floating-promises" 이 async 호출에 await가 없어서 경고가 나. 결과를 기다려야 하는지 아니면 의도적으로 안 기다리는지 판단해서, 전자면 await, 후자면 void + 에러 처리로 고쳐줘.
검수 리포트

TS 에러는 초보에게 암호다

error TS18048: 'u.email' is possibly 'undefined'. AI로 타입스크립트를 짜다 이 빨간 줄을 만나면, 초보의 첫 반응은 대개 둘 중 하나다. 그냥 any 로 막거나, ! 를 붙여 덮는다. 둘 다 에러는 사라지지만 런타임 버그를 남긴다.

이 사전은 그 에러를 사람 말로 옮긴다. "이건 이 값이 없을 수도 있다는 뜻이에요." 그리고 덮지 않고 제대로 고치는 요청 문장과 before/after를 준다. 항목마다 실제 tsc가 뱉은 원문(다크 터미널), 원인, 처방, 확인법이 붙는다.

대원칙: any 와 느낌표로 덮지 않는다

타입 에러를 없애는 가장 쉬운 길은 as any 나 value! 다. 하지만 그건 타입 시스템에게 거짓말을 하는 것이고, 실제로 undefined가 오면 앱이 터진다. 이 사전의 기본 방향은 좁히기(narrowing) 다. 옵셔널 체이닝(?.), 기본값(??), if 가드, 타입 정정으로 진짜 안전하게 만든다.

즉방형과 분기형

! 를 무조건 금지하지 않는다. 직전에 존재를 확인해 정말 안전하다면 정당하다. 다만 "빨간 줄 없애려고" 붙인 건지를 먼저 가른다.

실제 컴파일러가 근거다

에러 메시지는 지어내지 않았다. tsc --strict 를 돌려 실제로 확보한 원문 13종이 근거다. TS18048(possibly undefined), TS7006(implicit any), TS2322(not assignable), TS2339(no property), TS2554(argument count), TS2353(excess property), TS2683(this any) 등. before/after 코드도 그 에러를 내고 고친 실물이다.

수요는 실측됐다

이 사전을 만든 이유는 데이터다. 네이버 fe-news 6년치 80호를 교차 스캔했더니 react-typescript-cheatsheet가 5회로 가장 자주 언급된 저장소였다. 프런트엔드 개발자의 최대 반복 고통이 TS 타입이라는 신호다. css-menu(깨진 화면)·codelazy(부풀린 코드)에 이어, type-menu는 "빨간 줄"을 증상으로 잡는다.

쓰는 법 세 가지