ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [TS] Utility Types
    programing/Language 2020. 3. 18. 15:40

     

    안녕하세요, Einere입니다.

    (ADblock을 꺼주시면 감사하겠습니다.)


    이번 포스트에서는 Type Script의 Utility Types에 대해 알아보도록 하겠습니다.

     

     

    Utility Types

    타입스크립트에서는 타입 변환을 용이하게 하기 위해 몇가지 유틸리티 타입을 제공합니다. 이 유틸리티 타입은 전역으로 사용할 수 있습니다.

    해당 포스트에서 T는 타입, K는 키(속성), U는 유니온 타입을 의미합니다.

     

    Patial<T>

    T의 모든 속성이 선택 사항인 타입을 만들어줍니다. 즉, T의 모든 하위집합을 나타내는 타입을 반환합니다.

     

    interface Todo {
        title: string;
        description: string;
    }
    
    function updateTodo(todo: Todo, fieldsToUpdate: Partial<Todo>) {
        return { ...todo, ...fieldsToUpdate };
    }
    
    const todo1 = {
        title: 'organize desk',
        description: 'clear clutter',
    };
    
    const todo2 = updateTodo(todo1, {
        description: 'throw out trash',
    });

     

    Readonly<T>

    T의 모든 속성이 읽기전용인 타입을 만들어줍니다. 즉, 이 타입을 가진 변수는 재할당이 불가능합니다.

     

    interface Todo {
        title: string;
    }
    
    const todo: Readonly<Todo> = {
        title: 'Delete inactive users',
    };
    
    todo.title = 'Hello'; // Error: cannot reassign a readonly property

     

    Record<K, T>

    T를 타입으로 가지는 K의 속성들의 집합을 만들어줍니다. 이 유틸리티 타입은 특정 타입의 속성을 또다른 타입의 속성들에 매핑하는데 유용합니다.

     

    interface PageInfo {
        title: string;
    }
    
    type Page = 'home' | 'about' | 'contact';
    
    const x: Record<Page, PageInfo> = {
        about: { title: 'about' },
        contact: { title: 'contact' },
        home: { title: 'home' },
    };

     

    Pick<T, K>

    T에서 K만 추출한 타입을 만들어줍니다.

     

    interface Todo {
        title: string;
        description: string;
        completed: boolean;
    }
    
    type TodoPreview = Pick<Todo, 'title' | 'completed'>;
    
    const todo: TodoPreview = {
        title: 'Clean room',
        completed: false,
    };

     

    Omit<T, K>

    T에서 모든 속성을 고른 후, K를 제거한 타입을 만들어줍니다.

    interface Todo {
        title: string;
        description: string;
        completed: boolean;
    }
    
    type TodoPreview = Omit<Todo, 'description'>;
    
    const todo: TodoPreview = {
        title: 'Clean room',
        completed: false,
    };

     

    Exclude<T, U>

    U에 할당가능한 모든 속성을 T에서 제거한 타입을 만들어줍니다.

     

    type T0 = Exclude<"a" | "b" | "c", "a">;  // "b" | "c"
    type T1 = Exclude<"a" | "b" | "c", "a" | "b">;  // "c"
    type T2 = Exclude<string | number | (() => void), Function>;  // string | number

     

    Extract<T, U>

    U에 할당가능한 모든 속성을 T에서 추출한 타입을 만들어줍니다.

     

    type T0 = Extract<"a" | "b" | "c", "a" | "f">;  // "a"
    type T1 = Extract<string | number | (() => void), Function>;  // () => void

     

    NonNullable<T>

    T에서 nullundefined를 제거한 타입을 만들어줍니다.

     

    type T0 = NonNullable<string | number | undefined>;  // string | number
    type T1 = NonNullable<string[] | null | undefined>;  // string[]

     

    Parameters<T>

    함수 T의 파라미터들의 타입을 튜플 타입으로 만들어줍니다.

     

    declare function f1(arg: { a: number, b: string }): void
    
    type T0 = Parameters<() => string>;  // []
    type T1 = Parameters<(s: string) => void>;  // [string]
    type T2 = Parameters<(<T>(arg: T) => T)>;  // [unknown]
    type T4 = Parameters<typeof f1>;  // [{ a: number, b: string }]
    type T5 = Parameters<any>;  // unknown[]
    type T6 = Parameters<never>;  // never
    type T7 = Parameters<string>;  // Error
    type T8 = Parameters<Function>;  // Error

     

    ConstructorParameters<T>

    생성자 함수 T의 파라미터들의 타입을 추출한 타입을 만들어줍니다.

     

    type T0 = ConstructorParameters<ErrorConstructor>;  // [(string | undefined)?]
    type T1 = ConstructorParameters<FunctionConstructor>;  // string[]
    type T2 = ConstructorParameters<RegExpConstructor>;  // [string, (string | undefined)?]

     

    ReturnType<T>

    함수 T의 반환 값의 타입을 만들어줍니다.

     

    declare function f1(): { a: number, b: string }
    
    type T0 = ReturnType<() => string>;  // string
    type T1 = ReturnType<(s: string) => void>;  // void
    type T2 = ReturnType<(<T>() => T)>;  // {}
    type T3 = ReturnType<(<T extends U, U extends number[]>() => T)>;  // number[]
    type T4 = ReturnType<typeof f1>;  // { a: number, b: string }
    type T5 = ReturnType<any>;  // any
    type T6 = ReturnType<never>;  // any
    type T7 = ReturnType<string>;  // Error
    type T8 = ReturnType<Function>;  // Error

     

    InstanceType<T>

    생성자 함수 T로 생성된 인스턴스의 타입을 만들어줍니다.

     

    class C {
        x = 0;
        y = 0;
    }
    
    type T0 = InstanceType<typeof C>;  // C
    type T1 = InstanceType<any>;  // any
    type T2 = InstanceType<never>;  // any
    type T3 = InstanceType<string>;  // Error
    type T4 = InstanceType<Function>;  // Error

     

    Required<T>

    타입 T의 모든 속성을 필수로 만든 타입을 만들어줍니다.

     

    interface Props {
        a?: number;
        b?: string;
    };
    
    const obj1: Props = { a: 5 }; // OK
    const obj2: Required<Props> = { a: 5 }; // Error: property 'b' missing

     

    ThisParameterType<T>

    함수 T의 this파라미터의 타입을 추출합니다. 만약 this파라미터가 없다면 unknown이 됩니다.

    단, 해당 유틸리티 타입은 --strictFunctionTypes이 enable일 때 정상적으로 작동합니다.

     

    function toHex(this: Number) {
        return this.toString(16);
    }
    
    function numberToString(n: ThisParameterType<typeof toHex>) {
        return toHex.apply(n);
    }

     

    OmitThisParameter<T>

    함수 T에서 this파라미터를 제거합니다.

    단, 해당 유틸리티 타입은 --strictFunctionTypes이 enable일 때 정상적으로 작동합니다.

     

    function toHex(this: Number) {
        return this.toString(16);
    }
    
    // The return type of `bind` is already using `OmitThisParameter`, this is just for demonstration.
    const fiveToHex: OmitThisParameter<typeof toHex> = toHex.bind(5);
    
    console.log(fiveToHex());

     

    ThisType<T>

    해당 유틸리티 타입은 변환된 타입을 반환하지는 않습니다. 대신, 문맥적 this타입을 위한 마커로서 사용됩니다.

    해당 유틸리티 타입은 --noImplicitThis가 enable이어야 사용할 수 있습니다.

     

    type ObjectDescriptor<D, M> = {
        data?: D;
        methods?: M & ThisType<D & M>;  // Type of 'this' in methods is D & M
    }
    
    function makeObject<D, M>(desc: ObjectDescriptor<D, M>): D & M {
        let data: object = desc.data || {};
        let methods: object = desc.methods || {};
        return { ...data, ...methods } as D & M;
    }
    
    let obj = makeObject({
        data: { x: 0, y: 0 },
        methods: {
            moveBy(dx: number, dy: number) {
                this.x += dx;  // Strongly typed this
                this.y += dy;  // Strongly typed this
            }
        }
    });
    
    obj.x = 10;
    obj.y = 20;
    obj.moveBy(5, 5);

    많이 복잡하지만, 핵심은 moveBy함수 내부에서 사용되는 this의 타입은 D & M이 된다는 것입니다.

    만약 JS의 경우라면 moveBy 내부의 this는 methods를 가리키게 되겠죠.

     

     

    참고

    https://www.typescriptlang.org/docs/handbook/utility-types.html

     

    Utility Types · TypeScript

    Introduction # TypeScript provides several utility types to facilitate common type transformations. These utilities are available globally. Table of contents # Partial # Constructs a type with all properties of T set to optional. This utility will return a

    www.typescriptlang.org

     

    댓글

Designed by black7375.