~11 min · foundations, annotations, syntax, where-to-annotate
Level 0Curious
0 XP0/93 lessons0/23 achievements
0/100 XP to next level100 XP to go0% complete
"타입을 많이 적는 게 목표가 아니야. 중요한 경계에서 정확히 적고 나머지는 추론에 맡기는 게 목표야."
타입을 적을 수 있는 자리
변수, 함수 매개변수, 반환값, 객체 속성, 클래스 필드, 제네릭 인자처럼 TypeScript 곳곳에 타입을 적을 수 있어. 문법은 대부분 콜론 뒤에 타입을 놓는 형태야. name: string, count: number, function f(x: number): string처럼 읽으면 돼.
하지만 모든 자리에 적는다고 더 안전해지는 것은 아니야. const count: number = 3에서 : number는 컴파일러가 이미 아는 사실을 반복해. 반복은 소음이 되고, 값의 모양을 바꿀 때 함께 고쳐야 할 문서가 하나 더 늘어나. 추론이 정확한 지역 변수는 그냥 두는 편이 낫다.
경계에서는 명시성이 이겨
함수 매개변수와 공개 반환 타입은 다른 코드가 의존하는 문이야. 여기에는 타입을 명시하면 계약이 잘 보여. 특히 라이브러리의 공개 함수, API 계층, 상태 저장소처럼 변경 영향이 넓은 곳에서는 반환 타입을 적어 구현이 우연히 넓어지는 일을 막을 수 있어.
반면 함수 안에서 파생되는 작은 값은 추론에 맡겨. 입력과 출력 경계에 말뚝을 박고 그 사이 흐름은 컴파일러가 따라가게 하는 그림이 좋아. 타입 표기가 세금처럼 느껴진다면 대개 안쪽까지 손으로 장부를 복사하고 있는 거야.
넓게 적으면 정보를 잃을 수도 있어
const status: string = 'ready'라고 쓰면 정확한 리터럴 정보가 넓은 string으로 사라져. 컴파일러가 원래 더 좁게 알 수 있었는데 사람이 덜 정확한 타입을 덮어쓴 셈이지. 타입 표기는 언제나 정보를 더하는 것이 아니라 때로는 지워. 그래서 ‘이 표기가 추론보다 더 정확한가?’를 물어야 해.
타입은 경계에서 계약이고, 내부에서는 증거의 흐름이야. 경계는 명시하고 지역 계산은 추론에 맡겨. 이 균형이 코드와 타입을 함께 짧고 정확하게 유지해.
타입 별칭으로 반복을 줄여
같은 객체 모양이나 함수 시그니처가 반복되면 type이나 interface로 이름을 붙여. 여러 자리에 긴 인라인 타입을 복사하면 하나를 바꿀 때 계약이 갈라질 수 있어. 이름 붙인 타입은 단지 글자를 줄이는 도구가 아니라 도메인 개념을 코드에 세우는 일이야.
피파의 고백
초기에는 모든 변수에 타입을 붙인 코드를 ‘엄격한 코드’라고 착각했어. 실제로는 중요한 관계가 반복 표기 사이에 묻혔지. 지금은 공개 경계를 또렷하게 적고, 함수 안에서는 추론이 말하게 둬. 좋은 장부는 모든 거래를 두 번 베끼는 장부가 아니라 필요한 사실을 한곳에서 믿을 수 있게 하는 장부야.
Code
Annotation 이 사는 5개 자리·typescript
// 한 snippet 에 5개 annotation 위치 다.
// 1. 변수 annotation
const greeting: string = 'hi';
// 2. Parameter annotation
// 3. Return type annotation
function repeat(text: string, count: number): string {
return text.repeat(count);
}
// 4. Property annotation (interface 안)
interface User {
id: number;
name: string;
email: string | null;
}
// 5. Type parameter constraint
function first<T extends unknown[]>(arr: T): T[0] {
return arr[0];
}
first([1, 2, 3]); // number 반환
first(['a', 'b', 'c']); // string 반환
문에서 Annotate·typescript
// Over-annotation (noisy):
const x: number = 1; // 콜론 불필요 — inference 가 이미 알아
const names: string[] = ['Pippa', 'Dad']; // 불필요
const user: { name: string } = { name: 'Pippa' }; // 불필요
// 알맞은 크기 (문 규칙):
function makeUser(name: string, age: number): User { // 들어가는 문 + 나가는 문 — annotate
const id = generateId(); // 추론 — 깨끗
const stamped = { id, name, age, createdAt: new Date() }; // 추론 — 깨끗
return stamped; // return 이 User 기준으로 체크됨
}