"'possibly undefined' 라고 빨간 줄이 떠요"
TS18048function f(u: User) {
return u.email.toLowerCase();
// ~~~~~~~ possibly undefined
}function f(u: User) {
return u.email?.toLowerCase() ?? "";
}
사전 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 코드를 짜다 빨간 줄에 막히는 사람에게 도입 후보.
TS 에러 메시지는 영어에 코드번호(TS18048…)라 초보에겐 암호다. 이 사전은 그 메시지를 사람 말로 옮기고, any로 덮지 않고 제대로 고치는 요청 문장 + before/after를 준다. 전부 실제 tsc가 뱉은 원문 기준.
이 값이 undefined일 수 있어서 나는 TS18048 에러야. any로 막지 말고, 옵셔널 체이닝이나 기본값으로 안전하게 좁혀서 고쳐줘.
옵셔널 체이닝(?.) + 기본값(??), 또는 앞에서 가드로 좁힌다. any 로 덮지 않는다. 빨간 줄이 사라지고 undefined일 때 앱이 안 터지면 성공.
이 값이 undefined일 수 있어서 나는 TS18048 에러야. any로 막지 말고, 옵셔널 체이닝이나 기본값으로 안전하게 좁혀서 고쳐줘.
function f(u: User) {
return u.email.toLowerCase();
// ~~~~~~~ possibly undefined
}function f(u: User) {
return u.email?.toLowerCase() ?? "";
}타입 에러 나는데 그냥 any로 막아줘
이 값이 undefined일 수 있어서 나는 에러야. 옵셔널 체이닝이나 기본값으로 좁혀서 고쳐줘
왼쪽이 터미널에 뜨는 번호, 오른쪽이 사람 말이에요.
스킬로 깔아 두면 빨간 줄 원문만 붙여도 any 없이 고치는 문장으로 바꿔요.
/plugin marketplace add hanmariyang/giting-skills
/plugin install type-menu@giting
function f(u: User) {
return u.email.toLowerCase();
// ~~~~~~~ possibly undefined
}function f(u: User) {
return u.email?.toLowerCase() ?? "";
}const x = arr.find(n => n > 0);
return x + 1; // x 가 undefined 일 수 있음const x = arr.find(n => n > 0);
if (x === undefined) return 0;
return x + 1;const el = document.querySelector('.x')!;
el.textContent = 'hi'; // 없으면 런타임 터짐const el = document.querySelector('.x');
if (el) el.textContent = 'hi';| 증상 | 코드 | 유형 | 이렇게 말해도 | 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이 아님이 보장되는지 아니면 그냥 덮은 건지 판단해서, 후자면 제대로 좁혀줘. |
function f(items) {
return items.map(i => i.id);
}function f(items: { id: string }[]) {
return items.map(i => i.id);
}class C {
v = 1;
m() { return function() { return this.v; }; }
}class C {
v = 1;
m() { return () => this.v; }
}| 증상 | 코드 | 유형 | 이렇게 말해도 | AI에게 이렇게 |
|---|---|---|---|---|
| "'implicitly has any type' 라고 떠요" | TS7006 | 즉방형 | "매개변수에 빨간 줄" · "타입 안 적었더니 에러" · "함수 인자 any" | 이 함수 매개변수에 타입이 없어서 TS7006이 나. any로 두지 말고 실제 들어오는 값에 맞는 타입을 적어줘. |
| "'this implicitly has type any' 라고 떠요" | TS2683 | 즉방형 | "this 에서 에러" · "콜백 안에서 this" · "함수 안 this any" | 이 함수 안 this 가 TS2683으로 막혀. 화살표 함수로 바꿔서 바깥 this 를 쓰게 고쳐줘. |
const n: number = "3"; // 문자열을 숫자 자리에const n: number = 3;
// 문자열이 맞다면: const n = "3";function add(a: number, b: number) { return a + b; }
add(1); // b 빠짐add(1, 2);
// b 가 선택이라면: function add(a: number, b = 0)const fn: (x: number) => void = (x: string) => {};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로 안 맞아. 매개변수 타입을 기대하는 함수 타입에 맞추거나, 추론되게 타입을 지워서 고쳐줘. |
const o = { a: 1 };
console.log(o.b); // b 없음const o = { a: 1, b: 2 };
console.log(o.b);interface Opt { a: number }
const opt: Opt = { a: 1, b: 2 };interface Opt { a: number; b: number }
const opt: Opt = { a: 1, b: 2 };const arr: readonly number[] = [1, 2];
arr.push(3);const arr: readonly number[] = [1, 2];
const next = [...arr, 3];| 증상 | 코드 | 유형 | 이렇게 말해도 | 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 배열을 바꾸려다 에러가 나. 원본 수정 대신 새 배열을 만들어 반환하는 식으로 고쳐줘. |
function f(x: string | number) {
return x.toUpperCase();
}function f(x: string | number) {
return typeof x === "string" ? x.toUpperCase() : String(x);
}function move(dir: "up" | "down") {}
const d = "up";
move(d); // d 는 string 으로 추론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, 후자면 검증으로 고쳐줘. |
async function g(): Promise<number> { return 1; }
function use() {
const n: number = g(); // await 빠짐
}async function g(): Promise<number> { return 1; }
async function use() {
const n: number = await g();
}function save() { api.post(data); } // 실패해도 모름async function save() { await api.post(data); }| 증상 | 코드 | 유형 | 이렇게 말해도 | AI에게 이렇게 |
|---|---|---|---|---|
| "async 함수 결과가 Promise라고 떠요" | TS2322 | 즉방형 | "await 빠뜨림" · "Promise 가 숫자에 안 들어감" · "비동기 결과 타입 에러" | async 함수 결과가 Promise라 TS2322가 나. await를 붙이고 감싸는 함수도 async로 만들어서 고쳐줘. |
| "await 안 붙였다고 경고가 떠요" | floating-promise | 분기형 | "promise 를 안 기다림" · "async 호출 경고" · "no-floating-promises" | 이 async 호출에 await가 없어서 경고가 나. 결과를 기다려야 하는지 아니면 의도적으로 안 기다리는지 판단해서, 전자면 await, 후자면 void + 에러 처리로 고쳐줘. |
error TS18048: 'u.email' is possibly 'undefined'. AI로 타입스크립트를 짜다 이 빨간 줄을 만나면, 초보의 첫 반응은 대개 둘 중 하나다. 그냥 any 로 막거나, ! 를 붙여 덮는다. 둘 다 에러는 사라지지만 런타임 버그를 남긴다.
이 사전은 그 에러를 사람 말로 옮긴다. "이건 이 값이 없을 수도 있다는 뜻이에요." 그리고 덮지 않고 제대로 고치는 요청 문장과 before/after를 준다. 항목마다 실제 tsc가 뱉은 원문(다크 터미널), 원인, 처방, 확인법이 붙는다.
타입 에러를 없애는 가장 쉬운 길은 as any 나 value! 다. 하지만 그건 타입 시스템에게 거짓말을 하는 것이고, 실제로 undefined가 오면 앱이 터진다. 이 사전의 기본 방향은 좁히기(narrowing) 다. 옵셔널 체이닝(?.), 기본값(??), if 가드, 타입 정정으로 진짜 안전하게 만든다.
!(정말 안전한가 vs 그냥 덮은 건가), 리터럴 타입(고정 상수 vs 런타임 변수), floating promise(기다려야 하나 vs fire-and-forget). 무조건 한 답을 강요하지 않고 갈림길로 진단부터 시킨다! 를 무조건 금지하지 않는다. 직전에 존재를 확인해 정말 안전하다면 정당하다. 다만 "빨간 줄 없애려고" 붙인 건지를 먼저 가른다.
에러 메시지는 지어내지 않았다. 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는 "빨간 줄"을 증상으로 잡는다.