💻 프로그래밍

Type

타입

데이터의 종류를 분류하는 체계. 정적/동적 타이핑, 강타입/약타입 시스템으로 코드 안정성과 가독성을 높여 버그를 예방합니다.

📖 상세 설명

타입(Type)은 프로그래밍에서 데이터의 종류를 분류하고 정의하는 체계입니다. 변수나 표현식이 가질 수 있는 값의 집합과 그 값에 적용 가능한 연산을 명시하여, 컴파일러나 인터프리터가 데이터를 올바르게 처리할 수 있도록 안내합니다. 타입 시스템은 프로그램의 논리적 일관성을 보장하는 핵심 기반입니다.

기본 타입(Primitive Type)은 언어가 제공하는 가장 기초적인 데이터 형태로, number, string, boolean, null, undefined 등이 있습니다. 복합 타입(Composite Type)은 기본 타입을 조합하여 만든 구조체, 배열, 객체, 함수 타입 등입니다. TypeScript에서는 interface, type alias, union, intersection 등을 활용해 복잡한 도메인 모델을 정교하게 표현할 수 있습니다.

타입 시스템은 크게 두 가지 축으로 분류됩니다. 첫째, 정적(Static) vs 동적(Dynamic) 타이핑은 타입 검사 시점의 차이입니다. TypeScript, Java는 컴파일 타임에 타입을 검사하고, Python, JavaScript는 런타임에 검사합니다. 둘째, 강타입(Strong) vs 약타입(Weak)은 타입 변환의 엄격함을 나타냅니다. Python은 암묵적 형변환을 허용하지 않는 강타입, JavaScript는 자동 형변환이 일어나는 약타입입니다.

실무에서 타입 시스템은 세 가지 핵심 가치를 제공합니다. 첫째, 컴파일 타임 버그 예방으로 런타임 에러를 사전 차단합니다. 둘째, 코드가 곧 문서가 되어 함수의 입출력을 명확히 전달합니다. 셋째, IDE 자동완성과 리팩토링 지원으로 개발 생산성을 높입니다. 대규모 팀 프로젝트에서 TypeScript 도입이 표준이 된 이유입니다.

💻 코드 예제

// TypeScript 타입 정의 종합 예제

// 1. 기본 타입 (Primitive Types)
const userName: string = "홍길동";
const userAge: number = 28;
const isActive: boolean = true;
const nothing: null = null;
const notDefined: undefined = undefined;

// 2. 배열과 튜플
const scores: number[] = [95, 87, 92];
const tuple: [string, number] = ["서울", 37.5665]; // 고정 길이, 고정 타입

// 3. 객체 타입 정의 - Interface
interface User {
    id: number;
    name: string;
    email: string;
    role: "admin" | "user" | "guest"; // 리터럴 타입
    createdAt: Date;
    profile?: {                        // 선택적 속성
        bio: string;
        avatar: string;
    };
}

// 4. Type Alias와 Union Type
type ID = string | number;
type Status = "pending" | "approved" | "rejected";

type ApiResponse = {
    success: boolean;
    data: T;
    error?: string;
    timestamp: number;
};

// 5. 함수 타입 정의
function createUser(
    name: string,
    email: string,
    role: User["role"] = "user"  // Index Access Type
): User {
    return {
        id: Date.now(),
        name,
        email,
        role,
        createdAt: new Date()
    };
}

// 6. 제네릭 타입 활용
function fetchData(url: string): Promise> {
    return fetch(url)
        .then(res => res.json())
        .then(data => ({
            success: true,
            data: data as T,
            timestamp: Date.now()
        }));
}

// 7. 타입 가드 (Type Guard)
function isUser(obj: unknown): obj is User {
    return (
        typeof obj === "object" &&
        obj !== null &&
        "id" in obj &&
        "name" in obj &&
        "email" in obj
    );
}

// 8. 조건부 타입 (Conditional Type)
type NonNullable = T extends null | undefined ? never : T;
type ExtractArrayType = T extends (infer U)[] ? U : never;

// 사용 예시
const users: User[] = [createUser("Alice", "alice@example.com", "admin")];
const result: ExtractArrayType = users[0]; // User 타입

📊 언어별 타입 시스템 비교

언어 검사 시점 타입 강도 특징
TypeScript 정적 (컴파일) 강타입 구조적 타이핑, 점진적 적용 가능
Java 정적 (컴파일) 강타입 명목적 타이핑, 클래스 기반
Python 동적 (런타임) 강타입 덕 타이핑, Type Hints 지원
JavaScript 동적 (런타임) 약타입 암묵적 형변환 발생
Rust 정적 (컴파일) 강타입 소유권 시스템, 제로 코스트 추상화
Go 정적 (컴파일) 강타입 인터페이스 기반 다형성

💡 실무 팁: JavaScript 프로젝트는 TypeScript로 마이그레이션하면 버그를 40% 이상 줄일 수 있습니다. Python은 mypy와 Type Hints를 활용하세요.

🗣️ 실무 대화 예시

코드 리뷰: 타입 설계 논의 중

"이 API 응답에 any 쓰시면 안 돼요. 백엔드 스펙 보고 interface로 정확히 정의해주세요. 나중에 필드 바뀌면 TypeScript가 모든 사용처를 알려주거든요. any 쓰면 런타임에 터져요."

코드 리뷰: 타입 가드 활용

"unknown으로 받은 데이터는 타입 가드 함수 만들어서 검증해주세요. 'in' 연산자랑 typeof 조합하면 됩니다. assertion보다 안전하고, 가드 함수는 재사용도 되니까 utils에 모아두면 좋아요."

기술 면접: 타입 시스템 설명 요청

"정적 타이핑은 컴파일 타임에 타입을 검사해서 배포 전에 버그를 잡고, 동적 타이핑은 런타임에 검사해서 유연하지만 테스트 커버리지가 중요합니다. TypeScript는 JavaScript에 정적 타입을 얹어서 두 세계의 장점을 취한 거죠."

⚠️ 주의사항

1
타입 강제 변환 주의

JavaScript의 == 연산자나 + 연산자는 암묵적 형변환을 수행합니다. "5" + 3은 "53"이 되고, "5" - 3은 2가 됩니다. 항상 === 를 사용하고, Number(), String() 등 명시적 변환을 권장합니다.

2
any 타입 남용 금지

any는 타입 검사를 완전히 우회합니다. 급할 때 쓰기 쉽지만, 코드베이스 전체의 타입 안전성을 무너뜨립니다. 최소한 unknown을 쓰고 타입 가드로 좁히세요. ESLint의 no-explicit-any 규칙을 켜두세요.

3
타입 가드 활용하기

외부 데이터(API 응답, 사용자 입력)는 런타임에 타입이 보장되지 않습니다. typeof, instanceof, in 연산자를 활용한 타입 가드나 Zod 같은 런타임 검증 라이브러리로 데이터 무결성을 확보하세요.

🔗 관련 용어

📚 더 배우기