ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Typescript] Utility Types 유틸리티 타입
    front-end/Javascript&Typescript 2023. 7. 28. 01:19

     

    평소에 리액트  + 타입스크립트로 개발을 할때 interface 와 type 그리고 genric 위주로만 거의 사용 했던거같습니다.

     

    타입스크립트 유틸리티 타입은 타입스크립트의 강력한 기능 중 하나로, 타입 시스템을 보다 간편하고 효율적으로 사용할 수 있도록 도와줍니다. 

     

    그래서 타입 정의를 좀 더 효과적이고 , 안전하게 하고자 유틸리티 타입을 알아보면서0  프로젝트에 실제로 사용하면서 익히는 걸 목표로 하고 포스팅을 해보겠습니다.

     

     

    1. keyof

    interface User {
        id:number;
        name:string;
        age:number;
        gender:"M | F"
    }
    
    type UserKey = keyof User; // 'id' | 'name' | 'age' | 'gender'
    
    const kwnagmin:UserKey = 'name';
    const checkGender:UserKEy = 'male' // Error

    keyof 키워드를 사용하면 를 User inerface의 키값들을 union 형태로 받아올 수 있습니다.

    checkGender 변수에 'male' 이라는 값을 담을땐 User 프로퍼티 키값에 male이 없으니 에러가 납니다.

     

     

    2. partial<T>


    제네릭을 사용하여 주어진 타입 T의 모든 속성을 선택적으로 만들어주는 기능을 제공합니다.

    기존 타입 T의 모든 속성을 Optional(선택적)로 만들어주는 역할을 합니다. 이로 인해 해당 타입을 가진 변수 또는 객체의 속성을 모두 필수적이지 않게 만들어주는 효과를 갖게 됩니다.

    interface User {
        id:number;
        name:string;
        age:number;
        gender:"M | F";
    }
    
    //error: missing the following properties from type 'User': age, gender
    const profile:User = {
        id:1,
        name:'kwangmin'
    }
    
    
    // It works! 
     const profile:Partial<User> = {
        id:1,
        name:'kwangmin'
    }


    User프러퍼티를 Partial 을 사용하면 아래처럼 작동 된다고 보면 됩니다.

    // Looks like this!
    
    interface User {
        id:number;
        name:string;
        age?:number;
        gender?:"M | F";
    }

     

     

    3. Required<T>

    Required<T>는 Partial과 반대로 , 기존 타입 T의 모든 속성을 Required(필수적)로 만들어주는 역할을 합니다. 이로 인해 해당 타입을 가진 변수 또는 객체의 속성이 모두 필수적이게 됩니다.

    아래와 같은 interface가 있을때 , User의 age는 옵셔널 하기 때문에 profile에 age 프로퍼티가 없어도 에러가 안납니다. 

     

    interface User {
        id:number;
        name:string;
        age?:number;
    }
    
    const profile:User = {
        id:1,
        name:'kwangmin'
    }

     

    Required 를 적용하고 나면 age도 더이상 옵셔널 하지 않기때문에 age 프로퍼티도 profile에서 반드시 추가 해줘야 합니다.

    interface User {
        id:number;
        name:string;
        age?:number;
    }
    
    // Error Property 'age' is missing in type '{ id: number; name: string; }' but required in type 'Required<User>'.
    const profile:Required<User> = {
        id:1,
        name:'kwangmin'
    }

     

    4. Readonly<T>

    Readonly 는  말 그대로 읽기 전용 프로퍼티 입니다. 값이 수정이 되면 에러를 발생 시키는 유틸리티 입니다.

     

    아래 예시는 proifle의 age 의 값을 31 에서 29로 바꾸는것은 예샹처럼 잘 작동 됩니다.

    interface User {
        id:number;
        name:string;
        age:number;
    }
    
    const profile:User = {
        id:1,
        name:'kwangmin',
        age:31
    }
    
    // Possible !
    profile.age = 29;

     

    그러나 아래와 같이 Readonly 를 추가 해주고 , age의 값을 변경 시키려고 하면 에러가 납니다.

    interface User {
        id:number;
        name:string;
        age:number;
    }
    
    const profile:Readonly<User> = {
        id:1,
        name:'kwangmin',
        age:31
    }
    
    // Error Cannot assign to 'age' because it is a read-only property.
    profile.age = 29;

     

    5. Record< K, T >

     

    Record 의 첫번째 인자는 key , 두번째 인자는 type 입니다.

    Record<K, T>는 특정 키(K)와 그에 해당하는 값(T)으로 이루어진 객체를 생성하는 타입입니다. 이렇게 생성된 객체의 모든 키는 K 타입으로, 모든 값은 T 타입으로 지정됩니다.

     

    아래 코드를 Record를 적용하여 똑같이 작동하도록 해보겠습니다.

    interface Profile {
        name:string;
        age:number;
        married:boolean;
    }
    
    const profile:Profile = {
        name:'kwangmin',
        age:29,
        married:true
    }


    Interface to Record

    type profileKey = 'name' | 'age' | 'married';
    type profileValue = string | number | boolean;
    
    const profile:Record<profileKey,profileValue> = {
        name:'kwangmin',
        age:29,
        married:true
    }

     

    Record 를 함수로 된 예시도 한번 보겠습니다.
    아래 코드는 checkProfile 이라는 함수로 result 를 리턴 시키는데요, checkProfile 함수 안에 있는 result 객체에 타입을 선언 해주고싶으면 어떻게 해야 할까요?

    interface Profile {
        name:string;
        age:number;
        married:boolean;
    }
    
    const profile:Profile = {
        name:'kwangmin',
        age:29,
        married:true
    }
    
    const checkProfile = (user:Profile) => {
        const result = {
            name : user.name.length > 5,
            age : user.age > 19,
            married : user.married === false
        }
    
        return result;
    }
    
    const getValue =  checkProfile(profile);
    
    console.log(getValue);

    Record 를 이용하여 , 첫번째 인자로 Profile의 key 유니온 타입을 넣어주고 , 할당 된 값이 모두 boolean 타입 이기때문에 두번째 인자로

    boolean 을 넣어줍니다.

    interface Profile {
        name:string;
        age:number;
        married:boolean;
    }
    
    const profile:Profile = {
        name:'kwangmin',
        age:29,
        married:true
    }
    
    const checkProfile = (user:Profile) => {
        const result:Record<keyof Profile, boolean> = {
            name : user.name.length > 5,
            age : user.age > 19,
            married : user.married === false
        }
    
        return result;
    }
    
    const getValue =  checkProfile(profile);

     

    5. Pick<T,K>

    Pick은 선언해놓은 interface 에서 첫번재 인자로 선언한 interface명을 넣고 , interface에서 사용할 Key를 'Pick' 할 수 있습니다.

    말 그대로 고를 수 있다는겁니다.

    interface Profile {
        name:string;
        age:number;
        married:boolean;
    }
    
    const profile: Pick<Profile, 'name' | 'age'> = {
        name:'kwangmin',
        age:30
    }

     

    5. Omit<T,K>

    Omit은 Pick과 반대로 interface에서 key 값을 제외 하고 타입을 선언 하고싶을때 사용 합니다.
    Omit을 사용해서 name , age 제외 시켜줍니다. profile 객체엔 name, age 프로퍼티가 없어도 에러가 없이 잘 작동합니다.

    interface Profile {
        name:string;
        age:number;
        married:boolean;
    }
    
    const profile: Omit<Profile, 'name' | 'age'> = {
        married:true
    }


    아래와 같이 name 프로퍼티는 제외하고 age 타입을 number 에서 string 으로 바꿀 수 있습니다.

    interface User {
        name:string;
        age:number;
        hasCar:boolean;
    }
    
    const profile:Omit<User,'name'> & {age : string}= {
        name:'kwangmin',
        age:30, //Error. Should be string type.
        hasCar:true
    }

     

     

    5. Exclude<T1,T2>

    두 개의 제네릭 타입 매개변수 T1과 T2를 사용하여 타입 T1에서 T2에 할당 가능한 타입을 제거하는 역할을 합니다. 간단하게 설명하면, Exclude<T1, T2>는 T1에서 T2에 할당 가능한 타입들을 제외한 타입을 생성합니다. 이로 인해 T1과 T2가 다른 타입의 합집합을 만드는 효과를 갖습니다.

    Omit과 비슷하게 제거 혹은 제외 하는 기능을 갖고있지만 , Omit은 프로퍼티를 제거 및 제외 시키고 , Exculde 는 타입을 제거 및 제외 시킵니다.

    아래 코드를 보면 T2의 타입은 T1 타입에서 string을  제외한 number , boolean의 유니온 타입을 갖게 됩니다.

    type T1 = string | number | boolean;
    type T2 = Exclude<T1 ,string>



    6. NonNullable<T>

     

    NonNullable<T>는 T에서 null과 undefined를 제외한 타입을 생성합니다. 이로 인해 해당 타입을 가진 변수 또는 객체의 값은 null 또는 undefined가 될 수 없게 됩니다.

    type T1 = string | undefined | null | number 
    type T2 = NonNullable<T1>

     

     

Designed by Tistory.