// 객체 2개 합치기
type Merge<F, S> = {
[K in keyof F | keyof S]: K extends keyof S
? S[K]
: K extends keyof F
? F[K]
: never
}
type Merge<A, B> = Pick<A & B, keyof A | keyof B>
// &로 묶인 객체 하나로 합치기 ex) A & B => AB
type Merge<T> = Omit<T, never>
type Merge<T> = Pick<T, keyof T>
type Merge<T> = { [K in keyof T]: T[K] }
type AorB = 'a' | 'b'
type BorC = 'b' | 'c'
// 타입 모두 합치기
type AorBorC = AorB | BorC // 'a' | 'b' | 'c'
// 겹치는 타입만
type B = AorB & BorC // 'a'
&
가 가드역할을 한다.
type FromEntry<K, V> = { [P in K & string]: V }
K
가 string
인 것만 쏙 빼와서 레코드 타입으로 만들기
K extends string ? { [P in K]: V } : never
이런 식으로 string
타입인지 extends
로 확인할 필요 없음
모든 객체는 {}
에서 시작하므로 {}
를 extend
한다고 빈 객체가 아닐 수 있음
type True = { a: 1 } extends {} ? true : false // true
빈 객체는 Record<any, never>
나 { [key: string]: never }
임
type Empty = Record<any, never>
type True = {} extends Empty ? true : false
never
에 값을 할당할 수 없어서, 배열에도 넣을 수가 없음
type IsNever<T> = [T] extends [never] ? true : false
type Array = ['a', 'b', 'c']
type Elements = Array[number] // 'a' | 'b' | 'c'
extends
앞에 나온 파리미터로 유니온 요소가 하나씩 들어감. for-of
문으로 유니온 내 타입들을 순회하는 느낌
type IsUnion<T, C = T> = T extends C ? ([C] extends [T] ? false : true) : never
T
가 string | number
일 때, [T]
는 []
안으로 유니온 값이 하나씩 들어가지만,
[C]
는 유니온 타입이 통째로 []
로 들어감
[T] = [string] | [number]
[C] = [string | number]
객체의 키로 string
이나 number
타입이 쓰이는데,
해당 타입인지 여부는 string extends T
로 해당 타입을 string
이 확장하는지 확인한다.
T extends string
이런식으로 일반 타입을extends
뒤에만 써왔는데 충격..
type True = 'foo' extends string ? true : false // true
type False = string extends 'foo' ? true : false // false
type RemoveIndexSignature<T> = {
[K in keyof T as string extends K
? never
: number extends K
? never
: K]: T[K]
}
/^(\+|\-)?(\d*)?(\%)?$/
의 정규식을 같는 "+85%"
, 85%
, 85
문자를 파싱해서 [플러스 or 마이너스
, 숫자
, 단위
]로 반환해야 한다.
type ParseSign<T extends string> = T extends `${infer S}${any}`
? S extends '+' | '-'
? S
: ''
: ''
type ParsePercent<T extends string> = T extends `${any}%` ? '%' : ''
type ParseNumber<T extends string> =
T extends `${ParseSign<T>}${infer N}${ParsePercent<T>}` ? N : ''
type PercentageParser<A extends string> = [
ParseSign<A>,
ParseNumber<A>,
ParsePercent<A>
]
+, - 기호와 퍼센트 단위를 파싱하는 타입을 만들고
이를 활용해 숫자만 파싱하는 타입을 만들고
마지막에 모든 타입을 합쳐서 퍼센트를 파싱한다.
예술적이다
type StartsWith<T, U extends string> = T extends `${U}${any}` ? true : false
type StartsWith<T, U extends string> = T extends `${any}${U}` ? true : false
type Contains<T, U extends string> = T extends `${any}${U}${any}` ? true : false
값이 Required
했을 때랑 같은지 확인해서 옵셔널 키를 걸러내기
type RequiredOnly<T> = {
[K in keyof T as T[K] extends Required<T>[K] ? K : never]: T[K]
}
RequiredOnly<{a?: number, b?: string, c: boolean }> // === { c: boolean }
- 함수 오버로딩할 때 유용함
- 인자를 써야할 때 쓰고, 안 써야할 때 쓰게 만들 수 있음
type OptionalParam<T> = [] | [T]
const func = (...args: OptionalParam<boolean>) => {}
func() // ok
func(true) // ok