본문 바로가기
🟨 JavaScript 🟨/🟦TypeScript🟦

TypeScript - Utility Types

by 백씨네 2024. 2. 23.
728x90

1. keyof

interface User{
    id:number
    name:string
    age:number
    gender:"M" | "F"
}

type UserKey = keyof User // "id" | "name" | "age" | "gender"

const uk:UserKey = "id"
const uk2:UserKey = "score" // 오류 발생

keyof를 이용해서 객체 타입의 모든 키를 문자열 또는 숫자 리터럴 유티온 타입으로 추출할 수 있게 해 준다.

keyof 예시 1

객체의 키를 매개변수로 받는 함수를 정의할 때, 해당 객체 타입의 keyof를 이용하여 타입 안전성을 보장할 수 있다.

interface Person {
    name: string
    age: number
}

type PersonKey = keyof Person // 'name' | 'age'

function getProperty<T, K extends keyof T> (obj: T, key: K){
    return obj[key]
}

const person: Person = { name: "Alice", age:30 }
const personName = getProperty(person, "name") // 가능 - "Alice"
const personAge = getProperty (person, "age") // 가능 - 30
const personGender = getProperty (person, "gender") // Person에 gender가 없기 때문에 오류

keyof 예시 2

객체타입을 매핑하여 새로운 타입을 생성할 수 있다

type ReadonlyPerson = {
    readonly [P in keyof Person]: Person[P]
}

keyof는 typescript에서 타입의 안전성을 강화하고 타입 간의 관계를 더 명확하게 표현할 수 있도록 도와준다.

 

 

2. Partial

Partial은 타입을 옵셔널로 바꿔주는 역할을 한다. 기존에 선언되어 있던 interface가 옵셔널이 아니지만 옵셔널로 필요한 상황이 있을 때 사용할 수 있다.

Partial<T>로 작성할 수 있고 T는 변경할 interface가 들어온다.

interface User {
    id: number
    name: string
    age: number
    gender: "M" | "F"
}

// Partial<User>은 아래와 같은 형태라고 생각하면 된다.

//  interface User {
//        id?: number
//        name?: string
//        age?: number
//        gender?: "M" | "F"
//  }



let admin: Partial<User> = {
    id:1,
    name:"Bob",
    job : "manager"  // 오류 발생 
}

User의 interface를 옵셔널로 만든 것이기 때문에 User에 없는 job을 넣게 되면 오류가 발생한다.

 

 

3. Required

Partial과 반대로 모두 필수로 바꿔준다.

interface User{
    id: number
    name: stirng
    age?: number
}


let admin: Required<User> = {
    id: 1,
    name: "Bob",
    age : 30 // age를 안쓰면 오류 발생
}

User에서는 age가 옵셔널이었지만 admin 타입을 Required로 지정하였기 때문에 age도 필수로 넣어줘야 한다.

 

 

4. Readonly

이전에 typescript의 class를 공부하면서 사용해 본 readonly랑 역할은 같다.
하지만 Readonly<T>는 타입을 사용할 때 기존에 있던 타입에 readonly를 할당하는 것과 같다.

interface User{
    id: number
    name: string
    age?: number
}

let admin: Readonly<User> = {
    id: 1,
    name: "Bob",
}


admin.id=24 // 오류발생

Readonly를 이용해서 타입을 지정했기 때문에 id를 수정할 수 없게 된다.

 

 

5. Record

Record<K,T>에서 K는 key를 뜻하고, T는 type을 뜻한다.

사용 예시 1

유저의 학년별 점수를 입력한다 했을 때


interface Score {
    "1": "A" | "B" | "C" | "D"
    "2": "A" | "B" | "C" | "D"
    "3": "A" | "B" | "C" | "D"    
    "4": "A" | "B" | "C" | "D"
}

const score :Score = {    
    1: "A",    
    2: "B",    
    3: "A",    
    4: "C",
}

이렇게 작성할 수 있을 것이다. 이런 형태를 Recode를 사용한다면 더 간단하게 작성할 수 있다.


type Grade = "1" | "2" | "3" | "4"
type Score = "A" | "B" | "C" | "D"

const score :Record<Grade,Score>= {
    1: "A",    
    2: "B",    
    3: "A",    
    4: "C",
}

이렇게 작성할 수 있고, 객체의 key에는 Grade로 지정한 것만, 객체의 value에는 Score로 지정한 것만 사용가능하게 되어 타입을 지정하는데 안전성을 높일 수 있다.

사용 예시 2

interface User {
    id:number
    name:string
    age:number
}

function isValid(user:User) {
    const result = {
        id: user.id > 0,
        name: user.name !== "",
        age: user.age >0 
    }
    return result
}

이러한 예시 코드가 있을 때 result의 타입을 Recode를 이용해서 지정할 수 있다.

...

function isValid(user: User) {
    const result:Record<keyof User, boolean> = {
        id: user.id > 0,
        name: user.name !== "",
        age: user.age >0 
    }
    return result
}

keyof를 이용해서 User 인터페이스의 key값을 얻을 수 있고 result의 value 값은 boolean이므로 위의 예시와 같이 사용이 가능하다.

 

 

6. Pick

Pick<T, K>는 타입에서 원하는 key를 선택해서 사용하고 싶을 때 Pick을 사용한다.
이미 정의되어 있는 타입이 여러 개일 때 일부만 가져와서 쓸 수 있다.

interface User {
    id:number    
    name:string    
    age:number    
    gender : "M" | "F"
}



const admin: Pick<User, "id" | "name"> = {
    id: 1,
    name : "Bob"
}

 

 

7. Omit

Omit<T, K>는 Pick의 반대이다.
Type에서 일부를 선택했던 pick과 달리 Omit은 일부를 제외하고 사용할 수 있다.


interface User {
    id:number
    name:string
    age:number
    gender : "M" | "F"
}


const admin: Omit<User, "age" | "gender"> = {
    id: 1,
    name : "Bob"
}

 

 

8. Exclude

Exclude<T1, T2>는 두 가지 타입을 이용해서 작성을 하는데 T1의 타입에서 T2와 공통된 타입을 지우고 사용할 수 있다.

Omit과 비슷하다고 느낄 수 있다 하지만 Omit 은 객체타입에서 특정 속성을 제외할 때 사용하고, Exclude는 유니언 타입에서 특정 멤버 타입을 제외할 때 사용된다.

Omit은 객체의 구조를 변경하지만 Exclude는 타입의 구성을 변경한다.

type T1 = string | number | boolean
type T2 = string | boolean

type ExcludeType = Exclude<T1, T2> // number만 남게 된다.

 

9. NonNullable

NonNullable<type>은 타입에서 null, undefined를 제외한다.

type T1 = string | null | undefined | void
type T2 = NonNullable<T1>
반응형

'🟨 JavaScript 🟨 > 🟦TypeScript🟦' 카테고리의 다른 글

TypeScript - Generic  (2) 2024.02.22
TypeScript - class (feat.예시코드)  (1) 2024.02.22
TypeScript - function  (0) 2024.02.22
TypeScript - interface  (0) 2024.02.22
Jest를 이용한 TDD(Test-Driven Development)  (0) 2023.04.24

댓글