TypeScript로 더 안전한 코드 작성하기: 실용적인 가이드
1. TypeScript를 사용하는 이유
JavaScript는 유연한 언어이지만, 동적 타입 시스템 때문에 런타임 오류가 발생할 가능성이 높습니다. TypeScript는 정적 타입 시스템을 제공하여 코드 작성 시점에 오류를 방지하고, 유지보수를 쉽게 하며, 개발자 경험을 향상시키는 역할을 합니다.
2. TypeScript의 주요 기능과 안전한 코드 작성 방법
2.1 타입 주석과 타입 추론 활용
TypeScript는 명시적인 타입 주석을 지원하지만, 강력한 타입 추론 기능도 제공합니다. 이를 활용하면 가독성을 유지하면서도 타입 안정성을 확보할 수 있습니다.
// 명시적인 타입 주석 사용
let userName: string = "John";
// 타입 추론을 활용한 선언
let age = 30; // TypeScript는 자동으로 number 타입으로 인식
2.2 엄격한 타입 검사 (strict
옵션 활성화)
tsconfig.json
에서 strict
옵션을 활성화하면 TypeScript의 엄격한 타입 검사를 활용할 수 있습니다. 이를 통해 런타임 오류를 사전에 방지할 수 있습니다.
{
"compilerOptions": {
"strict": true
}
}
이 옵션을 활성화하면 null
및 undefined
처리, 암시적 any
타입 방지, 보다 정교한 타입 검사가 가능합니다.
2.3 인터페이스와 타입을 활용한 구조적 안정성 확보
객체의 구조를 명확하게 정의하면, 예기치 않은 속성 접근 오류를 방지할 수 있습니다.
interface User {
name: string;
age: number;
email?: string; // 선택적 속성
}
const user: User = {
name: "Alice",
age: 25,
};
2.4 유니온 타입과 교차 타입 활용
유니온 타입을 사용하면 특정 변수에 여러 타입을 허용할 수 있으며, 코드의 안전성을 높일 수 있습니다.
function getValue(value: string | number): string {
return `Value: ${value}`;
}
교차 타입을 활용하면 여러 타입을 결합하여 보다 강력한 타입 검사를 수행할 수 있습니다.
interface Employee {
name: string;
department: string;
}
interface Manager {
name: string;
teamSize: number;
}
type TeamLead = Employee & Manager;
const lead: TeamLead = {
name: "Bob",
department: "Engineering",
teamSize: 10,
};
2.5 타입 가드 (Type Guards) 활용
타입 가드를 활용하면 런타임에서 타입을 안전하게 검사할 수 있습니다.
function isString(value: any): value is string {
return typeof value === "string";
}
function printValue(value: string | number) {
if (isString(value)) {
console.log("String value:", value.toUpperCase());
} else {
console.log("Number value:", value.toFixed(2));
}
}
2.6 unknown
과 never
타입을 활용한 안전성 강화
unknown
:any
와 달리 사용 전에 반드시 타입 검사를 해야 합니다.never
: 발생할 수 없는 값의 타입을 명시하여 코드의 완전성을 보장합니다.
function handleValue(value: unknown) {
if (typeof value === "string") {
console.log("String:", value);
} else if (typeof value === "number") {
console.log("Number:", value);
} else {
console.log("Unknown type");
}
}
2.7 제네릭(Generic) 활용
제네릭을 활용하면 보다 재사용 가능하고 안전한 코드를 작성할 수 있습니다.
function identity<T>(value: T): T {
return value;
}
const num = identity<number>(10);
const str = identity<string>("Hello");
2.8 Readonly
, Partial
, Pick
, Omit
등 유틸리티 타입 활용
TypeScript의 유틸리티 타입을 활용하면 보다 안전한 데이터 모델을 구축할 수 있습니다.
interface User {
name: string;
age: number;
}
// 모든 속성을 읽기 전용으로 설정
const readonlyUser: Readonly<User> = {
name: "John",
age: 30,
};
// 특정 속성을 선택하여 사용
type UserNameOnly = Pick<User, "name">;
2.9 strictNullChecks
를 활용한 null
과 undefined
처리
TypeScript에서는 strictNullChecks
를 활성화하면 null
과 undefined
를 엄격하게 검사할 수 있습니다.
function getLength(value: string | null): number {
return value ? value.length : 0;
}
2.10 ESLint 및 Prettier와 함께 사용하여 코드 품질 유지
TypeScript를 사용할 때 ESLint와 Prettier를 적용하면 일관된 스타일과 코드 품질을 유지할 수 있습니다.
npm install --save-dev eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin prettier
ESLint 설정 (.eslintrc.json
):
{
"parser": "@typescript-eslint/parser",
"extends": ["plugin:@typescript-eslint/recommended"],
"rules": {
"@typescript-eslint/no-explicit-any": "warn"
}
}
3. 결론
TypeScript는 정적 타입 시스템을 제공하여 JavaScript의 한계를 보완하고, 더욱 안전한 코드를 작성할 수 있도록 도와줍니다. 타입 주석, 제네릭, 타입 가드, 유틸리티 타입 등의 기능을 활용하면 유지보수성이 뛰어난 코드를 만들 수 있습니다. 또한, ESLint 및 Prettier와 함께 사용하면 더욱 높은 코드 품질을 유지할 수 있습니다.
TypeScript를 적극적으로 활용하여 더욱 견고하고 안전한 웹 애플리케이션을 개발해 보세요!