enum은 타입스크립트의 기본 문법이다(자바스크립트에는 존재하지 않는다).
이 질문에서 타입은 문자열 튜플을 enum처럼 동작하는 객체로 바꿔야 한다.
게다가, 이넘의 속성은 파스칼 케이스가 선호된다.
만약 두 번째 인자가 true라면 값은 숫자 리터럴이여야 한다.
The enum is an original syntax of TypeScript (it does not exist in JavaScript).
In this question, the type should convert a given string tuple to an object that behaves like an enum.
Moreover, the property of an enum is preferably a pascal case.
If true is given in the second argument, the value should be a number literal.
type EnumNumber<T extends readonly string[],Index extends any[]=[]>=
Index['length'] extends T['length']?{}:
{
readonly [R in T[number] as Capitalize<R>]:T[Index['length']] extends R?Index['length']:Capitalize<R> extends keyof EnumNumber<T,[...Index,1]>?EnumNumber<T,[...Index,1]>[Capitalize<R>]:never;
}
type Enum<T extends readonly string[], N extends boolean = false> =
N extends true?EnumNumber<T>:
{
readonly [R in T[number] as Capitalize<R>]:R
}
만약 두 번째 인자가 false라면 튜플의 모든 타입을 Capitalize된 타입을 키로, 원래 타입을 value로 가지는 객체를 반환한다. 이때 모든 타입은 readonly이다.
만약 두 번째 인자가 true라면, 다음과 같은 과정을 거친다.
키 타입은 기존처럼 튜플의 모든 타입을 Capitalize된 타입으로 가진다.
재귀적으로 동작하며, 매 재귀의 타입은 인덱스 별로 다음과 같이 반환된다.
// ['a','b','c']에서 인덱스가 0인 경우
{
A:0,
['B'|'C']:그 뒤의 재귀 타입['B'|'C']
}
// ['a','b','c']에서 인덱스가 1인 경우
{
B:1,
['C']:그 뒤의 재귀 타입['C']
}
// ['a','b','c']에서 인덱스가 2인 경우
{
'C':2
}
이런 식으로 재귀적으로 동작하여 최종적으로는 숫자형태의 Enum을 반환한다.