2025. 1. 30. 22:11ㆍProgramming Language/Typescript
이번 글에서는 이펙티브 타입스크립트 6장의 내용을 정리하고, 타입 선언과 관련된 베스트 프랙티스를 살펴보겠습니다. 타입스크립트의 타입 시스템을 보다 효과적으로 활용하기 위한 가이드라인을 확인해보세요.
1. devDependencies에 TypeScript와 @types 추가하기
TypeScript는 개발 도구이므로 devDependencies에 포함시키는 것이 일반적입니다. 만약 전역 설치를 하거나 dependencies에 추가하면 팀원 간 TypeScript 버전 불일치 문제가 발생할 수 있습니다. 따라서, 프로젝트 내부에서 TypeScript 버전을 고정하여 관리하는 것이 좋습니다.
{
"devDependencies": {
"typescript": "^5.0.0",
"@types/node": "^18.0.0"
}
}
이렇게 하면 프로젝트에 TypeScript가 올바르게 설정되며, 타입 정의 파일(@types)도 함께 관리할 수 있습니다.
2. 타입 선언과 관련된 세 가지 버전 이해하기
TypeScript를 사용할 때는 다음 세 가지 버전이 서로 일치해야 합니다:
- 라이브러리 버전 (react, express 등)
- 타입 선언(@types) 버전 (@types/react, @types/express 등)
- TypeScript 버전 (프로젝트의 TypeScript 버전)
이들 버전이 일치하지 않으면 예상치 못한 타입 오류가 발생할 수 있습니다. 특히, 라이브러리 업데이트 후에는 @types 패키지도 함께 업데이트해야 합니다.
npm install react@18 @types/react@18
위처럼 라이브러리와 @types 패키지를 동일한 버전으로 맞추는 것이 중요합니다.
3. 공개 API에 등장하는 모든 타입을 익스포트하기
라이브러리를 만들 때, 내부에서만 사용하는 타입이 아니라면 반드시 export 해야 합니다. 그래야 라이브러리를 사용하는 개발자들이 타입을 쉽게 참조할 수 있습니다.
export interface User {
id: string;
name: string;
}
export function getUser(id: string): User {
return { id, name: "Henry" };
}
이처럼 API의 입력과 출력 타입을 명확히 제공하면 사용자가 라이브러리를 더욱 쉽게 활용할 수 있습니다.
4. API 주석에 TSDoc 사용하기
TypeScript에서는 JSDoc 스타일의 주석을 활용해 함수와 클래스의 사용 방법을 문서화할 수 있습니다.
/**
* 주어진 ID로 사용자를 조회합니다.
* @param id 조회할 사용자 ID
* @returns 조회된 사용자 객체
*/
export function getUser(id: string): User {
return { id, name: "Henry" };
}
JSDoc을 사용하면 IDE에서 자동으로 문서를 생성하고, 타입 정보를 보강할 수 있습니다.
5. 콜백에서 this에 대한 타입 제공하기
콜백 함수에서 this를 사용할 경우 명시적으로 타입을 지정해야 합니다.
interface Handler {
this: HTMLElement;
handleEvent(event: Event): void;
}
document.getElementById("btn")?.addEventListener("click", function (this: HTMLButtonElement, event) {
console.log(this.id); // 올바르게 타입 체크됨
});
위와 같이 this의 타입을 명확히 지정하면 this가 undefined로 평가되는 문제를 방지할 수 있습니다.
6. 오버로딩 타입보다는 조건부 타입을 사용하기
함수 오버로딩보다는 조건부 타입을 활용하는 것이 더 간결하고 유지보수가 쉽습니다.
type Result<T> = T extends string ? string[] : number[];
function process<T extends string | number>(input: T): Result<T> {
return typeof input === "string" ? input.split(" ") : [input];
}
이렇게 하면 여러 개의 함수 오버로딩을 선언할 필요 없이, 유연한 타입 처리가 가능합니다.
7. 의존성 분리를 위해 미러 타입 사용하기
필수가 아닌 의존성을 최소화하기 위해, 인터페이스를 활용한 미러 타입을 사용할 수 있습니다.
interface Logger {
log: (message: string) => void;
}
function doSomething(logger?: Logger) {
logger?.log("작업 수행 중...");
}
이렇게 하면 특정 라이브러리(winston, pino 등)에 종속되지 않고도 타입을 분리하여 활용할 수 있습니다.
8. 테스팅 타입의 함정에 주의하기
타입을 테스트할 때는 함수 타입의 동일성과 할당 가능성을 명확히 이해해야 합니다.
type Callback = (value: number) => void;
const fn: Callback = (value) => console.log(value);
여기서 fn의 타입이 Callback과 호환되는지 확인해야 합니다. 특히, 콜백을 포함하는 함수를 테스트할 때는 매개변수 타입도 철저히 검증해야 합니다.
마무리
이번 글에서는 이펙티브 타입스크립트 6장의 주요 내용을 정리했습니다. TypeScript의 타입 선언을 올바르게 활용하면 유지보수성과 안정성이 향상됩니다. 실제 프로젝트에서 위 내용을 적용해보면서 더 나은 타입 안전성을 확보해보세요!
'Programming Language > Typescript' 카테고리의 다른 글
이펙티브 타입스크립트: 8장 요약 및 핵심 정리 (0) | 2025.02.04 |
---|---|
이펙티브 타입스크립트: 7장 요약 및 핵심 정리 (1) | 2025.02.03 |
이펙티브 타입스크립트: 5장 요약 및 핵심 정리 (0) | 2025.01.29 |
이펙티브 타입스크립트 4장: 요약 및 핵심 정리 (4) | 2025.01.25 |