배열(튜플)을 받아, 각 원소의 값을 key/value로 갖는 오브젝트 타입을 반환하는 타입을 구현하세요.
type TupleToObject<T extends readonly (number|string|symbol)[]> = {[K in T[number]]:K}
튜플의 T[number]를 하면 유니온 타입으로 지정이 되고, 유니온 타입에 있는 값을 각각 키와 밸류로 갖는 mapped type이라고 정의했다.
다음과 같은 상황에서는 사용 측에서 에러가 나야하는 것도 문제에 정의되어 있었다
// @ts-expect-error
type error = TupleToObject<[[1, 2], {}]>
이러한 에러를 둔 이유는 mapped type의 키값에는 string|number|symbol만 들어갈 수 있기 때문이다.
그래서 이러한 사항을 고려함과 동시에, TupleToObject라는 타입명의 의미를 살리고자
들어올 수 있는 제네릭을 readonly (number|string|symbol)[]로 고정시켰다
해당 문제는 as const 개념과typeof, Mapped type 개념에 대한 문제였다
우선 as const suffix에 대한 개념을 알아볼 수 있다.
특정 변수 선언 시 뒷 부분에 as const를 붙이면 해당 변수에 할당된 값의 모든 프로퍼티들은 자동적으로 readonly가 되며,
number나 string같은 범용적인 타입이 아닌 리터럴 타입으로 선언되게 된다
// req.url의 타입은 string(x),"https://example.com"(o)
// req.method의 타입은 string(x),"get"(o)
const req = { url: "https://example.com", method: "GET" } as const;
그리고 typeof 개념도 확인할 수 있다.
typeof는 일반 js의 연산자로도 활용할 수 있지만, 타입 선언 시에도 들어갈 수 있다.
타입 선언시에 들어간다는 것은 무엇을 의미할까?
예를 들어
a라는 변수에 들어가는 값을 1이라는 리터럴 타입으로 지정할 수 있다.
let a:1=1;
// 아래 코드는 에러 x
a=1;
// 아래 코드는 에러 o(1이라는 리터럴 타입에 2는 들어갈 수 없기 때문)
a=2;
이걸 확인하면
다음 코드에서 js와는 다른 부분(즉 타입을 지정해주는 부분)이 보일 것이다
let value:number=1;
:number는 해당 변수에 들어갈 타입을 지정해주는 부분이고,
:number를 제외한 나머지 부분은 일반 js에서도 사용하는 것 처럼 변수를 선언하는 부분이다.
여기서 변수에 들어갈 타입을 지정해주는 부분에 typeof 변수명을 사용하면 그 변수에 할당된 타입을 그대로 사용할 수 있다
const a:'hello'|'world'='hello'
// 아래 코드는 let b:'hello'|'world'와 같음
let b:typeof a
// 아래 코드는 type TypaA='hello'|'world'와 같음
type TypeA=typeof a
js의 typeof연산자와 헷갈릴 수 있음에 주의하자.
js의 typeof연산자는 값이 할당되는 곳에 나오는 일종의 함수라고 생각하면 편하다
const a=1;
// typeof 1을 typeof(a)라고 생각하면 편하다(*실제 동작은 아님*)
// 아래 코드는 const b='nubmer'와 같다는 것을 알 수 있다
const b=typeof a
대부분의 풀이가 나의 풀이와 비슷했다
https://www.typescriptlang.org/docs/handbook/2/everyday-types.html