한 걸음씩

[TypeScript] 리터럴, 유니온/교차 타입, 제네릭, 유틸리티 타입 본문

TypeScript

[TypeScript] 리터럴, 유니온/교차 타입, 제네릭, 유틸리티 타입

winter17 2023. 7. 26. 18:31

 

◆ 리터럴, 유니온/교차 타입

 

▷ Literal Types

// userName1의 타입을 문자열 리터럴 'Bob'으로 유추
const userName1 = 'Bob'
// userName2의 타입을 string 또는 number로 지정
let useName2: string | number = 'Tom'

// Job이라는 타입은 문자열 리터럴 police, developer, teacher 중 하나만 가능한 유니온 타임
type Job = 'police' | 'developer' | 'teacher'

interface User{
    name: string // 문자열 타입
    job: Job // 위에서 정의한 Job 타입(문자열 리터럴 타입)
}
// user 상수는 User 인터페이스를 따를 객체로 초기화
const user:User = {
    name: 'Bob', // name은 Bob 문자열 값을 가짐
    job: 'police' // job은 police로 문자열 리터럴 타입 값 중 하나를 가지고 있음
}

 

▷ Union Types

// 식별 가능한 유니온 타입
// Car, Mobile 인터페이스는 각각 name, color 프로퍼티를 가진다
// 이 프로퍼티는 식별 가능한 유니온 타입을 사용하기 위해 리터럴 타입으로 정의되어 있다
interface Car{
    name: 'car' // 문자열 리터럴 타입 'car'로 정의
    color: string
    start(): void
}
interface Mobile{
    name: 'mobile' // 문자열 리터럴 타입 'mobile'로 정의
    color: string
    call(): void
}
// getGift함수에서 gift 매개변수의 타입은 Car 또는 Mobile이 될 수 있다
function getGift(gift: Car | Mobile){
    console.log(gift.color)
    // gift.name을 통해 해당 객체의 타입을 구별할 수 있다
    // if문에서 특정 프로퍼티 값을 비교하여 객체의 타입을 정확하게 판별할 수 있다
    if(gift.name === 'car'){
        gift.start()
    }else{
        gift.call()
    }
}

 

▷ Intersection Types

  • 유니온 타입이 or이라면, 교차 타입은 and
// Intersection types
interface Car{
    name: string
    start() :void
}
interface Toy{
    name: string
    color: string
    price: number
}

const toyCar: Toy & Car = {
    name : '타요',
    start(){},
    color : 'blue',
    price : 1000,
}

 


제네릭

function getSize(arr: number[] | string[]): number{
    return arr.length
}
const arr1 = [1, 2, 3]
getSize(arr1) // 3

// 매개변수의 타입을 바꿨지만 동일한 함수를 사용하고 싶다면 함수 오버로드, 유니온 타입 사용
const arr2 = ['a', 'b', 'c']
getSize(arr2)

위처럼 작성할 수도 있지만 번거롭기 때문에 아래처럼 제네릭 방법을 사용한다

// Generic
function getSize<T>(arr: T[]): number{
    return arr.length
}
// 아래처럼 타입을 직접 지정하지 않더라도 타입스크립트가 판단함
const arr1 = [1, 2, 3]
getSize<number>(arr1) // 3

const arr2 = ['a', 'b', 'c']
getSize<string>(arr2) // 3

const arr3 = [false, true, true]
getSize<boolean>(arr3) // 3

const arr4 = [{}, {}, { name: 'Tim'}]
getSize(arr4) // 4

 

interface Mobile<T>{
    name: string
    price: number
    // option은 어떤 타입일지 모를 때 any보단 제네릭
    option: T
}
const m1: Mobile<object> = {
    name: 's1',
    price: 1000,
    option: {
        color: 'red',
        coupon: false,
    }
}
const m2: Mobile<string> = {
    name: 's2',
    price: 900,
    option: 'good'
}

 

interface User{
    name:string
    age: number
}
interface Car{
    name: string
    color: string
}
interface Book{
    price: number
}
// 위의 인터페이스를 사용하여 인스턴스 생성
const user: User = { name: 'a', age: 10}
const car: Car = {name: 'Bmw', color: 'red'}
const book: Book = {price: 3000}

// 제네릭 타입 T를 사용하여 매개변수 data를 제한함
// <T extends {name: string}>구문은 T가 {name: string} 형태를 가져야 한다는 제약 조건 의미
// data 매개변수는 name 프로퍼티를 가져야 하는 객체만 전달할 수 있음
function showName<T extends {name: string}>(data: T): string{
    return data.name
}
showName(user)
showName(car)
showName(book) // 에러 발생: book 인스턴스는 name프로퍼티를 가지지 않기 때문

유틸리티 타입

 

▷ keyof 

  • 인터페이스의 모든 프로퍼티 key들을 유니온 형태로 가져온다
interface User{
    id: number
    name: string
    age: number
    gender: 'm' | 'f'
}
type UserKey = keyof User // 'id' | 'name' | 'age' | 'gender'

const uk:UserKey = 'age'

 

▷ partial<T>

  • 프로퍼티를 모두 '선택'으로 
interface User{
    id: number
    name: string
    age: number
    gender: 'm' | 'f'
}

let admin: Partial<User> = {
    id: 1,
    name: 'Bob',
    job: '' // 인터페이스에 없는 프로퍼티 사용시 에러 발생
}

 

▷ Required<T>

  • 모든 프로퍼티를 '필수'로
interface User{
    id: number
    name: string
    age: number
}

let admin: Required<User> = {
    id: 1,
    name: 'Bob',
    age: 30,
}

 

▷ Readonly

  • 모든 프로퍼티를 읽기 전용으로
interface User{
    id: number
    name: string
    age?: number
}

let admin: Readonly<User> = {
    id: 1,
    name: 'Bob',
}
// admin.id = 4 // 수정 불가능

 

▷ Record<K, T>

  • 키 타입 'K'와 값 타입 'T'를 사용하여 객체를 생성
type Grade = '1' | '2' | '3' | '4'
type Score = 'A' | 'B' | 'C' | 'D' | 'F'
const score: Record<Grade, Score> = {
    1: 'A',
    2: 'C',
    3: 'B',
    4: 'D',
}

 

// Record<K, T>
interface User{
    id: number
    name: string
    age: number
}
function isValid(user: User){
    const result: Record<keyof User, boolean> = {
        id: user.id > 0,
        name: user.name !== '',
        age: user.age > 0,
    }
    return result
}

 

▷ Pick<T, K>

  • 인터페이스 또는 타입 'T' 에서 특정 프로퍼티 키들 'K'만 선택하여 새로운 타입 생성
interface User{
    id: number
    name: string
    age: number
    gender: 'M' | 'W'
}
const admin: Pick<User, 'id' | 'name'> = {
    id: 0,
    name: 'Bob',
}

 

▷ Omit<T, K>

  • 인터페이스 또는 타입 'T'에서 특정 프로퍼티 키들 'K'를 제거하여 새로운 타입을 생성
interface User{
    id: number
    name: string
    age: number
    gender: 'M' | 'W'
}
const admin: Omit<User, 'age' | 'gender'> = {
    id: 0,
    name: 'Bob',
}

 

▷ Exclude<T1, T2>

  • 타입 'T1'에서 'T2'에 해당하는 타입을 제거
type T1 = string | number | boolean
type T2 = Exclude<T1, number | string>

 

▷ NonNullable<Type>

  • 타입 'Type'에서 'null'과 'undefined'를 제거하여 새로운 타입을 생성
type T1 = string | null | undefined | void
type T2 = NonNullable<T1>

[출처] 코딩앙마 | https://youtu.be/5oGAkQsGWkc

'TypeScript' 카테고리의 다른 글

[TypeScript] class, interface 연습문제  (0) 2023.08.05
[TypeScript] 함수 연습 문제 function, call signatures, generic  (0) 2023.08.03
[TypeScript] Class, Interface  (0) 2023.08.03
[TypeScript] Functions  (0) 2023.08.03
[TypeScript] Type  (0) 2023.08.03