0. 문제
배열이 주어지면, 이를 객체로 변경하세요(key와 value는 제공된 배열에 존재해야 합니다)
1. 설명
/* _____________ Your Code Here _____________ */
type TupleToObject<T extends readonly (string|number)[]> = {[P in T[number]]: P}
type MyType = TupleToObject<typeof tupleMix> // 확인용
/* _____________ Test Cases _____________ */
import type { Equal, Expect } from '@type-challenges/utils'
const tuple = ['tesla', 'model 3', 'model X', 'model Y'] as const
const tupleNumber = [1, 2, 3, 4] as const
const tupleMix = [1, '2', 3, '4'] as const
type cases = [
Expect<Equal<TupleToObject<typeof tuple>, { tesla: 'tesla'; 'model 3': 'model 3'; 'model X': 'model X'; 'model Y': 'model Y' }>>,
Expect<Equal<TupleToObject<typeof tupleNumber>, { 1: 1; 2: 2; 3: 3; 4: 4 }>>,
Expect<Equal<TupleToObject<typeof tupleMix>, { 1: 1; '2': '2'; 3: 3; '4': '4' }>>,
]
// @ts-expect-error
type error = TupleToObject<[[1, 2], {}]>
- typeof tuple이란 ? readonly ["tesla", "model 3", "model X", "model Y"]이다.
- 이 typeof tuple을 TupleToObject에 주입한다
- 들어온 T는 readonly (string|number)[] -> type은 string인 것도 있고 number인 것도 있기 때문.
- cases 안에 들어있는 string, number, string과 number가 섞여있는 tuple 모두 통과한다.
- 빈 object는 string | number가 아니기 때문에 error가 발생한다
추가설명
1.
type TupleToObject<T extends readonly number[]> = {[P in T[number]]: P}
를 사용하면 tupleNumber만 통과한다고 생각했다 -> 맞다
type TupleToObject<T extends readonly string[]> = {[P in T[number]]: P}
을 사용하면 tuple만 통과한다고 생각했다 -> 이 또한 맞다
type TupleToObject<T extends readonly string[]| number[]> = {[P in T[number]]: P}
을 사용하면 tupleNumber와 tuple 두개는 통과하고, tupleMix는 통과하지 못할 것이라 생각했다 -> 또잉? tuple만 통과하고 나머지는 통과하지 못했다.
type TupleToObject<T extends readonly number[]| string[]> = {[P in T[number]]: P}
은 tupleNumber만 통과하고 나머지는 통과하지 못했다.
type TupleToObject<T extends readonly number[] | string[] > = {[P in T[number]]: P}
Type 'readonly ["tesla", "model 3", "model X", "model Y"]' does not satisfy the constraint 'string[] | readonly number[]'.
Type 'readonly ["tesla", "model 3", "model X", "model Y"]' is not assignable to type 'readonly number[]'.
Type 'string' is not assignable to type 'number'.
readonly arr type이 string[] | readonly number[]을 만족시키지 못한다는 것. 뭔가 감이 잡힌다.
둘 다 readonly를 빼보자
type TupleToObject<T extends number[] | string[] > = {[P in T[number]]: P}
다 에러가 생긴다.
답이 나왔다! readonly로 전해준 type에서(typeof tuple이란 ? readonly ["tesla", "model 3", "model X", "model Y"]이다.) readonly를 내 나름대로 제외하려고 하니 에러가 생긴 것. 그러면 두개 다 readonly를 추가해주면 마지막 tupleMix만 빼고 통과할 것이다
-> 정답이다!
그러면 tupleMix또한 통과시키기 위해 새로운 readonly type을 추가해보자
type TupleToObject<T extends readonly number[] | readonly string[] | readonly (string|number)[] > = {[P in T[number]]: P}
통과한다!
이걸 짧게 줄여 쓰면
type TupleToObject<T extends readonly (string|number)[]> = {[P in T[number]]: P}
가 될 수 있다.
그런데 왜 number이지?
const tupleRandomNumber = ['10', 2, 3, 4] as const
Expect<Equal<TupleToObject<typeof tupleRandomNumber>, { 10: '10'; 2: 2; 3: 3; 4: 4 }>>,
뒤에서 쓰는 number가 index라고 예상은 했는데 눈으로 확인하고 싶어졌다.
type index = number
type TupleToObject<T extends Readonly<(number|string)[]> > = {[P in T[index]]: P}
좌항에서 나오는 number와는 완전히 다른 number가 쓰이고 있었다.
그냥 T의 index를 하나하나 돌면서 뽑아낸다는 의미로 사용되었다는 것을 알 수 있다.
'✍ 공부 > TypeScript' 카테고리의 다른 글
[type-challenges] Length of Tuple (0) | 2023.05.23 |
---|---|
[type-challenges] First of Array (0) | 2023.05.23 |
[type-challenges] Readonly (0) | 2023.05.16 |
[type-challenges] Pick (1) | 2023.05.16 |
[ 러닝 타입스크립트 ] 챕터 7. 인터페이스 (0) | 2023.03.07 |