JavaScript 에서 옮기기
이미 있는 코드에 타입을 조금씩 붙이는 순서입니다.
한꺼번에 옮기지 않습니다
이미 돌아가고 있는 JavaScript 코드에 타입을 붙이는 일입니다. 전부 한 번에 바꾸려 하면 오류가 수백 개씩 쏟아집니다. 순서가 있습니다.
- 설정을 느슨하게 열고 시작합니다(
strict: false). - 파일 이름을
.ts로 바꿉니다. 한 번에 하나씩입니다. - 막히는 자리를
any로 잠시 막습니다. - 바깥에서 들어오는 값부터 제대로 된 타입을 붙입니다.
- 설정을 하나씩 엄격하게 올립니다.
4번이 순서상 중요합니다. 가장 자주 터지는 자리가 거기이기 때문입니다 — 서버 응답, 사용자 입력, 저장소에서 꺼낸 값.
any 로 막아 두면 어떻게 되나
let data: any = JSON.parse('{"name":"홍길동"}'); console.log(data.name); console.log(data.nmae); console.log(data.age.toFixed(1));
타입 오류가 하나도 나지 않았습니다. 오타도, 없는 속성을 파고드는 것도 그대로 지나가 실행할 때 터집니다 — TypeScript 를 쓰기 전과 같습니다.
그래서 any 는 잠시 막아 두는 것이지 끝이
아닙니다. 옮기는 동안 남겨 두고, 하나씩 걷어냅니다.
출력을 둘로 적어 둔 것은 실행할 때 나는 오류의 문구가 브라우저마다 다르기 때문입니다(JS 7.1). 타입 검사가 내는 문구는 어느 브라우저에서든 같습니다 — 같은 컴파일러가 내는 것이기 때문입니다.
바깥에서 들어오는 값 다루기
JSON.parse 가 무엇을 돌려줄지 코드는 모릅니다.
unknown 으로 받고(1.5) 확인하는 함수를 하나
두는 것이 흔한 방법입니다.
const raw: unknown = JSON.parse('{"name":"홍길동"}'); interface User { name: string; } function isUser(value: unknown): value is User { return typeof value === "object" && value !== null && "name" in value; } if (isUser(raw)) console.log(raw.name); else console.log("모양이 다릅니다");
반환 타입이 boolean 이 아니라
value is User 입니다. 2.5 에서 "함수로 빼면
좁힌 것이 풀린다" 고 했던 자리인데, 이렇게 적으면 좁혀 줍니다.
if 안쪽에서 raw.name 이
되는 것이 그 증거입니다. 이런 함수를 타입 가드라고 부릅니다.
붙이고 나면
interface User { name: string; age: number; } function adults(users: User[]): string[] { return users.filter(u => u.age >= 19).map(u => u.name); } console.log(adults([ { name: "홍길동", age: 27 }, { name: "김철수", age: 15 } ]).join(", "));
filter 와 map 안의
u 에 타입을 적지 않았습니다. 배열의 타입을 한 번
적어 두면 안쪽은 따라옵니다. 이것이 붙이고 난 뒤에 얻는 것입니다.
처음에 자주 걸리는 것
JSON.parse(text) as User 라고 적으면 오류가
사라집니다. 확인한 것이 아니라 그렇다고 우긴 것이라, 실제 모양이
다르면 그대로 터집니다. 1.6 의 ! 와 같은
성격입니다.
오류가 수백 개 나오면 어디부터 손댈지 알 수 없습니다.
noImplicitAny 부터, 그다음
strictNullChecks 처럼 하나씩 켭니다.
옮기는 동안 넣은 any 는 표시를 남겨 두세요.
// TODO: 타입 붙이기 같은 주석 하나면 나중에
찾을 수 있습니다.
직접 해보기
{ title: string; pages: number } 모양인지 확인하는
타입 가드를 만들고, 맞으면 제목을 출력하세요.
interface Book {
title: string;
pages: number;
}
function isBook(value: unknown): value is Book {
if (typeof value !== "object" || value === null) return false;
return "title" in value && "pages" in value;
}
const raw: unknown = JSON.parse('{"title":"입문","pages":320}');
if (isBook(raw)) console.log(raw.title, raw.pages);
else console.log("모양이 다릅니다");
위 out-any 예제의 any 를
제대로 된 타입으로 바꾸면 어느 줄이 오류로 잡히는지 확인하세요.
let data: { name: string } = … 로 바꾸면 data.nmae 와 data.age 두 줄이 모두 잡힙니다. 실행하지 않고도 잡힙니다 — 그것이 옮기는 값입니다.이 단원의 정리
- 느슨한 설정으로 열고 파일을 하나씩 옮깁니다.
any는 잠시 막아 두는 것이지 끝이 아닙니다.- 바깥에서 들어오는 값부터 제대로 된 타입을 붙입니다.
value is User로 적으면 그 함수가 타입을 좁혀 줍니다.as는 확인이 아니라 우기는 것입니다.