한 걸음씩
[TypeScript] 리터럴, 유니온/교차 타입, 제네릭, 유틸리티 타입 본문
◆ 리터럴, 유니온/교차 타입
▷ 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 |