KNOW-HOW/SCRIPT

[ TypeScript 타입 서술어(Type Predicate) ]

코리안심슨 2024. 9. 10. 08:37

1. 타입 서술어란?

타입 서술어는 TypeScript에서 특정 스코프 내의 변수 타입을 좁히는(narrowing) 데 사용되는 특별한 반환 타입입니다.
함수가 true를 반환할 때, TypeScript는 인자의 타입을 특정 타입으로 취급합니다.



2. 기본 구조

function 함수이름(매개변수: 타입): 매개변수 is 특정타입 {
     return 불리언_표현식;
}


3. 간단한 예시: 문자열 체크

function isString(value: unknown): value is string {
    return typeof value === 'string';
}

// 사용 예:
function processValue(value: unknown) {
    if (isString(value)) {
        // 여기서 value는 string 타입으로 취급됩니다.
        console.log(value.toUpperCase());
    } else {
        console.log("Value is not a string");
    }
}


4. 실용적인 예시: 사용자 정의 타입 체크

interface User {
    name: string;
    email: string;
}

interface Admin {
    name: string;
    role: string;
}

function isUser(value: any): value is User {
    return (
        typeof value === 'object' &&
        value !== null &&
        'name' in value &&
        'email' in value
    );
}

function isAdmin(value: any): value is Admin {
    return (
        typeof value === 'object' &&
        value !== null &&
        'name' in value &&
        'role' in value
    );
}

// 사용 예:
function processAccount(account: unknown) {
    if (isUser(account)) {
        // account는 User 타입으로 취급됩니다.
        console.log(`Sending email to ${account.email}`);
    } else if (isAdmin(account)) {
        // account는 Admin 타입으로 취급됩니다.
        console.log(`Admin role: ${account.role}`);
    } else {
        console.log("Unknown account type");
    }
}


5. 고급 예시: 제네릭과 함께 사용

function isArrayOfType<T>(arr: unknown, check: (item: unknown) => item is T): arr is T[] {
    return Array.isArray(arr) && arr.every(check);
}

// 사용 예:
const numbers = [1, 2, 3, 4, 5];
const mixedArray = [1, 'two', 3, 'four', 5];

if (isArrayOfType(numbers, (item): item is number => typeof item === 'number')) {
    // numbers는 number[] 타입으로 취급됩니다.
    console.log(numbers.reduce((sum, num) => sum + num, 0));
}

if (isArrayOfType(mixedArray, (item): item is number => typeof item === 'number')) {
    // 이 조건은 false이므로 이 블록은 실행되지 않습니다.
    console.log("This won't be logged");
}

 

6. 실제 사용 시나리오: API 응답 처리

interface ApiResponse {
    status: 'success' | 'error';
    data?: unknown;
    error?: string;
}

function isSuccessResponse(response: ApiResponse): response is ApiResponse & { status: 'success', data: unknown } {
    return response.status === 'success' && 'data' in response;
}

function handleApiResponse(response: ApiResponse) {
    if (isSuccessResponse(response)) {
        // response.data가 존재함을 TypeScript가 알고 있습니다.
        console.log("Success:", response.data);
    } else {
        // response는 { status: 'error', error: string } 타입으로 추론됩니다.
        console.log("Error:", response.error);
    }
}

// 사용 예:
handleApiResponse({ status: 'success', data: { id: 1, name: 'John' } });
handleApiResponse({ status: 'error', error: 'Not found' });


7. 주의사항
- 타입 서술어는 런타임에 영향을 주지 않습니다. 순수하게 TypeScript의 타입 체킹을 위한 것입니다.
- 타입 서술어 함수의 로직이 실제로 타입을 올바르게 체크하는지 확인해야 합니다.
- 타입 서술어의 효과는 해당 조건문 블록 내에서만 유효합니다.