type Enum<T extends readonly string[], N extends boolean = false> = {
readonly [P in keyof T as P extends `${infer _ extends number}` ? Capitalize<T[P]> : never]:
N extends true
? P extends `${infer U extends number}` ? U : never
: T[P]
}
Solution by alex-altay #35184
type Enum<T extends readonly string[], N extends boolean = false> = {
readonly [P in keyof T as P extends `${number}` ? Capitalize<T[P]> : never]: N extends true ? P extends `${infer R extends number}` ? R : never : T[P]
}
Solution by 2083335157 #35034
// T extends readonly 一定要加readonly,那么才是字面量类型
type MapKey<T extends readonly unknown[]> = T extends readonly [any, ...infer rest] ? MapKey<rest> | rest['length'] : never
type Enum<T extends readonly string[], N extends boolean = false> = {
readonly [K in MapKey<T> as Capitalize<T[K]>]: N extends true ? K : T[K]
}
Solution by ouzexi #34225
// ============= Your Code Here =============
type GetIndex<T extends readonly any[], S extends string> = T extends readonly [... infer R, infer L] ?
L extends S ? R["length"] : GetIndex<R, S>
: never
type Enum<T extends readonly string[], N extends boolean = false> = N extends true ?
{
readonly [P in T[number]as Capitalize<P>]: GetIndex<T, P>
}
: {
readonly [P in T[number]as Capitalize<P>]: P
}
Solution by Steven4857 #33064
type Copy<T> = {
[P in keyof T]: T[P];
};
type Wrap<
T extends readonly string[],
N extends boolean = false,
Count extends 1[] = []
> = T extends readonly [
infer L extends string,
...infer R extends readonly string[]
]
? Readonly<Record<Capitalize<L>, N extends true ? Count["length"] : L>> &
Wrap<R, N, [...Count, 1]>
: {};
type Enum<T extends readonly string[], N extends boolean = false> = Copy<Wrap<T, N>>;
Solution by Vampirelee #32620
type Enum<
T extends readonly string[],
N extends boolean = false,
C extends 0[] = []
> = T extends readonly [infer F, ...infer R extends readonly string[]]
? Omit<
{
readonly [K in F as Capitalize<K & string>]: N extends true
? C["length"]
: F;
} & Enum<R, N, [...C, 0]>,
never
>
: {};
Solution by vangie #32323
type EnsureArray<T, R = string> = T extends R[] ? T : never;
type Enum<
T extends readonly string[],
B extends boolean = false,
R extends Readonly<Record<string, any>> = Readonly<{}>,
Index extends unknown[] = []
> = T extends readonly [infer F, ...infer Rest]
? Enum<
Readonly<EnsureArray<Rest>>,
B,
Readonly<
R & {
[K in F & string as Capitalize<K>]: B extends true
? Index["length"]
: K;
}
>,
[...Index, unknown]
>
: R;
Solution by gearonixx #31474
思路和17一样是递归,从第一个开始递归,然后通过额外传递一个从零开始的数组来取长度得到index,每次递归到下一项把数组长度+1。
type Indexof<
T extends readonly unknown[],
Key,
LengthArr extends unknown[] = []
> = T extends readonly[infer First, ...infer Rest]
? Key extends First
? LengthArr["length"]
: Indexof<Rest, Key, [...LengthArr, unknown]>
: never;
type Enum<T extends readonly string[], N extends boolean = false> = {
readonly [Key in T[number] as Capitalize<Key>]: N extends false ? Key : Indexof<T,Key>;
};
Solution by GrinZero #30621
type Capitalize<S extends string> = S extends `${infer C}${infer Rest}` ? `${Uppercase<C>}${Rest}` :S
type ParseInt<T extends string,Acc extends number[]= []> = Equal<`${Acc['length']}`,T> extends true ? Acc['length'] : ParseInt<T,[...Acc,0]>
type GetIndex<T,K> = ParseInt<Exclude<{[Key in keyof T as T[Key]]:Key}[K],number>>
type Enum<T extends readonly string[], N extends boolean = false> = {
readonly [Key in T[number] as Capitalize<Key>] :N extends false ? Key : GetIndex<T,Key>
}
Solution by idebbarh #30437
type GetTupleUntilTarget<T extends readonly string[], S extends string> =
T extends readonly [infer F, ...infer R extends readonly string[]]
? S extends F
? []
: [F, ...GetTupleUntilTarget<R, S>]
: []
type Enum<T extends readonly string[], N extends boolean = false> =
N extends false
? {
readonly [P in T[number] as Capitalize<P>]: P
}
: {
readonly [K in T[number] as Capitalize<K>]: GetTupleUntilTarget<T, K>['length']
}
Solution by jazelly #27909
type UseIndex<T extends readonly unknown[], k extends string, U extends unknown[] = []> = T extends [infer L, ...infer R] ? [L] extends [k] ? U['length']
: UseIndex<R, k, [...U, unknown]> : -1
type Enum<T extends readonly any[], B extends boolean = false> = {
+readonly [K in T[number]]: B extends true ? UseIndex<T, K> : K
}
Solution by wuxin0011 #27568
type Enum<T extends readonly string[], N extends boolean = false> = {
readonly [I in keyof T as I extends `${number}` ? Capitalize<T[I]> : never]: N extends true ? StringToNumber<I> : T[I]
}
type StringToNumber<S> = S extends `${infer N extends number}` ? N : never
Solution by Pixoll #26922
type Enum<
T extends readonly string[],
N extends boolean = false
> =
T extends readonly [
...infer Init extends string[],
infer Last extends string
]
? Omit<
{
readonly [K in Capitalize<Last>]:
N extends true
? Init["length"]
: Last
} & Enum<Init, N>,
never
>
: {}
Solution by dsvictor94 #26334
type Enum<T extends readonly string[], N extends boolean = false> =
{ readonly [P in keyof T as P extends `${number}` ? Capitalize<T[P]> : never]:
N extends true ?
P extends `${infer I extends number}` ? I : never :
T[P] };
// old way
// type IndexOf<T extends readonly any[], U, _Counter extends any[] = []> = T extends readonly [infer F, ...infer R] ? (F extends U ? _Counter[`length`] : IndexOf<R, U, [..._Counter, F]>) : -1;
// type IsUniqueKeys<T extends readonly string[]> = T extends readonly [infer F extends string, ...infer R extends string[]] ? (-1 extends IndexOf<R, Capitalize<F>> & IndexOf<R, Uncapitalize<F>> ? IsUniqueKeys<R> : false) : true;
// type Enum<T extends (IsUniqueKeys<T> extends true/*Check Unique(optional)*/ ? readonly string[] : never), N extends boolean = false> = Readonly<{ [P in T[number]as Capitalize<P>]: N extends true ? IndexOf<T, P> : P }>;
Solution by E-uler #24780
type Enum<T extends readonly string[], N extends boolean = false> = {
readonly [K in keyof T as K extends `${number}` ? Capitalize<T[K]> : never]:
N extends false ? T[K] : K extends `${infer I extends number}` ? I : never
}
Solution by flavianh #24718
// 你的答案
type TupleToIndex<T extends readonly any[]> = T extends readonly [
infer F,
...infer O
] ? TupleToIndex<O>| O['length']
:never
type Enum<T extends readonly string[], N extends boolean = false> = {
readonly [ K in TupleToIndex<T> as Capitalize<T[K]>]: N extends true? K : T[K]
}
Solution by walker-hzx #24676
// 你的答案
type Enum<
T extends readonly string[],
N extends boolean = false
> = {
[
Key in keyof T
as Key extends `${infer I extends number}`
? Capitalize<T[I]>
: never
]: N extends false
? T[Key]
: Key extends `${infer I extends number}`
? I
: never
}
Solution by jxhhdx #23915
// your answers
type Enum<
T extends readonly string[],
B extends boolean = false,
> = {
readonly [
Key in keyof T as Key extends `${infer I extends number}`
? Capitalize<T[I]>
: never
]: B extends false
? T[Key]
: Key extends `${infer I extends number}`
? I
: never
}
Solution by snakeUni #23589
type TupleToEnumObject<
T extends any[],
S extends boolean = false,
Result extends object = {},
All extends any[] = []
> = T extends [infer F extends string | number | symbol, ...infer R]
? TupleToEnumObject<
R,
S,
Result & {
readonly [K in F extends string ? Capitalize<F> : F]: S extends false
? K extends T[number]
? K
: K extends string
? Uncapitalize<K>
: K
: All['length']
},
[...All, 0]
>
: Result
Solution by TKBnice #22864
type Enum<
T extends readonly string[],
B extends boolean = false,
> = {
readonly [
Key in keyof T as Key extends `${infer I extends number}`
? Capitalize<T[I]>
: never
]: B extends false
? T[Key]
: Key extends `${infer I extends number}`
? I
: never
}
Solution by drylint #22259
type Merge<T,U> = {
[key in keyof (T&U)]: key extends keyof T ? T[key] : key extends keyof U ? U[key] : never
};
type EnumAttribute<T extends string, N extends boolean, I extends number> = {
readonly [key in Capitalize<T>]: N extends true ? I : T
};
type Enum<T extends readonly string[], N extends boolean = false, C extends unknown[]=[]> =
[...T] extends [infer F extends string, ...infer Rest extends readonly string[]] ?
Merge<EnumAttribute<F, N, C['length']>, Enum<Rest, N, [...C, 0]>> : {};
Solution by Karamuto #22000
type Enum<T extends readonly string[], N extends boolean = false> = {
readonly [K in keyof T as K extends `${infer F extends number}` ? Capitalize<T[K]> : never]:
N extends true ? K extends `${infer F extends number}` ? F : never
: T[K];
}
Solution by yeyunjianshi #21757
type MergeProperty<T extends Record<PropertyKey, any>> = { [key in keyof T]: T[key] };
type Enum<T extends readonly string[], N extends boolean = false, Arr extends number[] = []> = MergeProperty<
T extends readonly [
infer First extends string,
...infer Rest extends string[]
]
? { readonly [Key in Capitalize<First>]: N extends true ? Arr['length'] : First } & Enum<Rest, N, [...Arr, 1]>
: {}
>;
// TEST
const OperatingSystem = ['macOS', 'Windows', 'Linux'] as const;
const Command = ['echo', 'grep', 'sed', 'awk', 'cut', 'uniq', 'head', 'tail', 'xargs', 'shift'] as const;
type R1 = Enum<[]>;
type R2 = Enum<typeof OperatingSystem>;
type R3 = Enum<typeof OperatingSystem, true>;
type R4 = Enum<typeof Command, true>;
type R5 = Enum<typeof Command>;
Solution by zqiangxu #21624
type Merge<T extends Record<PropertyKey, any>> = { [K in keyof T]: T[K] }
type Enum<
T extends readonly string[],
N extends boolean = false,
E extends object = {},
I extends unknown[] = []
> = T extends readonly [infer F extends string, ...infer R extends string[]]
? N extends true
? Merge<{
readonly [P in Capitalize<F>]: I['length']
} & Enum<R, N, E, [...I, unknown]>>
: Merge<{
readonly [P in Capitalize<F>]: F
} & Enum<R, N, E>>
: E
Solution by milletlovemouse #21560
// your answers
type StrToNum<S extends string,A extends any[] = []> = `${A['length']}` extends S ? A['length'] : A extends [...infer Rest] ? StrToNum<S,[...Rest,1]> : A
type Enum<T extends readonly string[], N extends boolean = false> = {
readonly [K in keyof T as T[K] extends string ? Capitalize<T[K]> : never] : N extends false ? T[Exclude<K,number>] : StrToNum<Exclude<K,number>>
}
Solution by YqxLzx #21045
// TODO
type PascalCase<T extends string> = Capitalize<T>
type StringToNumber<T> = T extends `${infer N extends number}` ? N : never
type Enum<T extends readonly string[], N extends boolean = false> = {
[P in keyof T as T[P] extends string ? PascalCase<T[P]> : never]:
N extends true
? StringToNumber<P>
: T[StringToNumber<P>]
}
This solution passes all cases, though PascalCase is not fully implemented, but I think it's not the focus of this question.
Solution by zhaoyao91 #20619
// your answers
type GetElmIdx<T extends readonly any[], K, Ret extends any[] = []> = T extends readonly [infer First, ...infer Rest] ? Equal<First, K> extends true ? Ret['length'] : GetElmIdx<Rest,K, [...Ret, unknown]> : Ret['length']
type Enum<T extends readonly string[], N extends boolean = false> = {
readonly [K in T[number]as Capitalize<K>]: N extends false ? K : GetElmIdx<T, K>
}
Solution by Rebornjiang #20599
type FindIndexInArray<key extends string, T extends readonly unknown[], N extends any[] = []> = [...T] extends [infer F, ...infer R]
? key extends F
? N['length']
: FindIndexInArray<key, R, [...N, 1]>
: -1;
type Enum<T extends readonly string[], N extends boolean = false> = {
readonly [key in T[number] as key extends `${infer F}${infer R}` ? `${Uppercase<F>}${R}` : never]: N extends true ? FindIndexInArray<key, T> : key;
};
Solution by CaoXueLiang #19039
type Enum<T extends readonly string[], N extends boolean = false, Count extends any[] = [], Result extends Record<string, number | string> = {}> =
T extends readonly [infer S extends string, ...infer R extends string[]]
? Enum<R, N, [...Count, any], Result & Record<Capitalize<S>, N extends true ? Count['length'] : S>>
: { readonly [P in keyof Result]: Result[P] };
Solution by BulatDashiev #16903
// your answers
type Enum<
T extends readonly string[],
N extends boolean = false,
R extends {} = {}
> = T extends readonly [...infer Head extends string[], infer Tail extends string]
? Enum<Head, N, R & Record<Capitalize<Tail>, N extends true ? Head['length']: Tail>>
: { readonly [P in keyof R]: R[P]; }
;
Got this idea from astak16, that if I process from the tail, I can get the ordinal number without counting it myself. I feel that mine is the neatest solution among those that I have read.
Solution by alexfung888 #16490