TypeScript

[ TypeScript ] type-challenges - 00011-easy-tuple-to-object

만두맨두 2023. 7. 21. 18:27

00011-easy-tuple-to-object

[ 문제 설명 ]
Given an array, transform it into an object type and the key/value must be in the provided array.

[ 문제 ]

type TupleToObject<T extends readonly any[]> = any

[ 예시 ]
const tuple = ['tesla', 'model 3', 'model X', 'model Y'] as const

type result = TupleToObject<typeof tuple> 
// expected { 'tesla': 'tesla', 'model 3': 'model 3', 'model X': 'model X', 'model Y': 'model Y'}

시작하기 전에,,
4번과 7번 문제는 정답에 대한 설명 없이 몰랐던 지식 위주로 설명했었는데요 ..!
11번 문제부터는 몰랐던 지식과 더불어 왜 이렇게 풀어야 하는지를 좀 더 설명하도록 하겠습니다 : )


const assertion

 

const tuple = ['tesla', 'model 3', 'model X', 'model Y'] as const

예시의 tuple을 보면 ' as const '라는 것을 볼 수 있는데, 이에 대해 이야기 해보겠습니다.

 

우선 먼저 알아야 할 것은 let과 const의 차이에요.
let은 값을 언제든 변경할 수 있기 때문에 primitive type으로 추론이 되고,
const는 값을 변경할 수 없기 때문에 literal type으로 추론이 됩니다.

let str1 = 'str1' // string
const str2 = 'str2' // "str2"

 

그런데 let도 literal type으로 추론할 수 있는 방법이 있는데, 그게 바로 ' as const '입니다.

그리고 그걸 const assertion이라고 불러요.

let str1 = 'str1' as const // "str1"

 

그럼 여기서 하나의 의문이 들게 될거에요.
" 저렇게 할거면 그냥 const를 사용하면 되지 않나 ? "

맞아요, primitive type에선 const assertion 대신 const를 사용하는 게 효율적이죠.


혹시 객체나 배열에서 타입 추론이 어떻게 되는지 본 적 있으신가요 ?

const arr1 = ['123', '456'] // string[]
const arr2 = ['123', 456] // (string | number)[]
const arr3 = [123, 456] // number[]

const obj1 = { a: 1, b: 2 }
// {
//     a: number;
//     b: number;
// }

const로 선언되었지만, 속성값은 언제든지 변경할 수 있기 때문에 속성값들의 타입이 primitive type으로 추론됩니다.
객체와 배열에도 ' as const'를 사용해볼까요 ?

const arr1 = ['123', '456'] as const // readonly ["123", "456"]

const obj1 = { a: 1, b: 2 } as const
// {
//     readonly a: 1;
//     readonly b: 2;
// }

const obj2 = { a: 1 as const, b: 2 }
// {
//     a: 1;
//     b: number;
// }

primitive type으로 추론되었던 객체와 배열의 속성값들이 literal type으로 추론되었어요.
이렇게 된다면 객체와 배열에서도 타입 안정성을 보장할 수 있게 됩니다 👍👍

인덱스 접근 타입

배열과 객체인 타입들은 어떻게 접근할까요 ?

배열은 T[number], 객체는 T[string]으로 접근할 수 있습니다.

좀 더 자세히 설명해드릴게요 !

 

const arr = [1, 2, 3] as const; // readonly [1, 2, 3]

arr의 타입은 ' readonly [1, 2, 3] '입니다.
그리고 저희는 이 타입을 유니온 타입으로 가져오고 싶은 상황이에요.
이 때, T[number]를 사용하면 됩니다.

const arr = [1, 2, 3] as const;

type ArrType = typeof arr; // readonly [1, 2, 3]

ArrType[number] // 1 | 2 | 3

 

그럼 객체에서도 적용시켜볼까요 ?

객체에는 T[string]을 사용합니다.

const obj = { a: 1, b: 2 } as const;

type ObjType = typeof obj;
// {
//     readonly a: 1;
//     readonly b: 2;
// }

ObjType[string] // 1 | 2

[ 정답 ]
type TupleToObject<T extends readonly any[]> = {
  [key in T[number]]: key
}​

 


1. T는 const assertion된 배열 형태의 타입이 들어오기 때문에 'readonly any[]'를 extends 시켜준다.
2. object로 만들어야 하기 때문에 중괄호를 둘러준다.
3. 인덱스 접근 타입을 사용해 들어온 타입들을 유니온 타입으로 변경시켜준다.
4. mapped type인 in을 통해 유니온 타입을 순회하여 key: value 형태로 만들어준다.

 

 

https://medium.com/@seungha_kim_IT/typescript-3-4-const-assertion-b50a749dd53b

 

TypeScript 3.4: const assertion

TypeScript 3.4 버전에는 const assertion 이라는 기능이 추가되었습니다.

medium.com

https://blog.toycrane.xyz/typescript%EC%97%90%EC%84%9C-%ED%9A%A8%EA%B3%BC%EC%A0%81%EC%9C%BC%EB%A1%9C-%EC%83%81%EC%88%98-%EA%B4%80%EB%A6%AC%ED%95%98%EA%B8%B0-e926db079f9

 

Typescript에서 효과적으로 상수 관리하기

const assertion and enum

blog.toycrane.xyz