yunliuyan / type-challenges

typescript-challenges
0 stars 2 forks source link

00009-tuple-to-enum-object #9

Open yunliuyan opened 1 year ago

yunliuyan commented 1 year ago

Tuple to Enum Object hard #tuple #template-literal

by Ryo Hanafusa @softoika

Take the Challenge    日本語

枚举是 TypeScript 的原始语法(JavaScript 中不存在)。 因此,通过转译,它被转换为如下形式:

let OperatingSystem;
(function (OperatingSystem) {
    OperatingSystem[OperatingSystem["MacOS"] = 0] = "MacOS";
    OperatingSystem[OperatingSystem["Windows"] = 1] = "Windows";
    OperatingSystem[OperatingSystem["Linux"] = 2] = "Linux";
})(OperatingSystem || (OperatingSystem = {}));

在这个问题中,类型应该将给定的字符串元组转换为行为类似于枚举的对象。 此外,枚举的属性优选是属性与值相等情况。

Enum<["macOS", "Windows", "Linux"]>
// -> { readonly MacOS: "macOS", readonly Windows: "Windows", readonly Linux: "Linux" }

如果在第二个参数中给出“true”,则该值应该是数字文字。

Enum<["macOS", "Windows", "Linux"], true>
// -> { readonly MacOS: 0, readonly Windows: 1, readonly Linux: 2 }

测试案例

import type { Equal, Expect } from '@type-challenges/utils'

const OperatingSystem = ['macOS', 'Windows', 'Linux'] as const
const Command = ['echo', 'grep', 'sed', 'awk', 'cut', 'uniq', 'head', 'tail', 'xargs', 'shift'] as const

type cases = [
  Expect<Equal<Enum<[]>, {}>>,
  Expect<Equal<
  Enum<typeof OperatingSystem>,
  {
    readonly MacOS: 'macOS'
    readonly Windows: 'Windows'
    readonly Linux: 'Linux'
  }
  >>,
  Expect<Equal<
  Enum<typeof OperatingSystem, true>,
  {
    readonly MacOS: 0
    readonly Windows: 1
    readonly Linux: 2
  }
  >>,
  Expect<Equal<
  Enum<typeof Command>,
  {
    readonly Echo: 'echo'
    readonly Grep: 'grep'
    readonly Sed: 'sed'
    readonly Awk: 'awk'
    readonly Cut: 'cut'
    readonly Uniq: 'uniq'
    readonly Head: 'head'
    readonly Tail: 'tail'
    readonly Xargs: 'xargs'
    readonly Shift: 'shift'
  }
  >>,
  Expect<Equal<
  Enum<typeof Command, true>,
  {
    readonly Echo: 0
    readonly Grep: 1
    readonly Sed: 2
    readonly Awk: 3
    readonly Cut: 4
    readonly Uniq: 5
    readonly Head: 6
    readonly Tail: 7
    readonly Xargs: 8
    readonly Shift: 9
  }
  >>,
]

Back Share your Solutions Check out Solutions

Related Challenges

10・Tuple to Union 11・Tuple to Object 730・Union to Tuple 3188・Tuple to Nested Object
yunliuyan commented 1 year ago

思路

获取元组的下标数组,然后通过Capitalize强制转成对应的字符串属性即为enum的属性值。 然后通过第二个参数来判断是否显示下标值还是key值。

代码实现

const OperatingSystem = ['macOS', 'Windows', 'Linux'] as const

type TupleKeys<T extends readonly any[]> = T extends readonly [infer R, ...infer args]
? TupleKeys<args> | args['length']
: never

type MyEnum<T extends readonly any[], bol = false> = {
   readonly [key in TupleKeys<T> as Capitalize<T[key]>]: bol extends false ? T[key] : key
}

type obj = MyEnum<typeof OperatingSystem>
type num = MyEnum<typeof OperatingSystem, true>
Janice-Fan commented 1 year ago
type FindIndex<T extends readonly any[], K, ACC extends unknown[] = []> = T extends readonly [infer F, ...infer RT]
  ? K extends F
    ? ACC['length']
    : FindIndex<RT, K, [...ACC, unknown]>
  : never;

type Enum<T extends readonly any[], B = false> = {
    readonly [k in T[number] as Capitalize<k>]: B extends true ? FindIndex<T, k> : k;
} 

type stringEnum = Enum<["macOS", "Windows", "Linux"]>
// -> { readonly MacOS: "macOS", readonly Windows: "Windows", readonly Linux: "Linux" }

type numberEnum = Enum<["macOS", "Windows", "Linux"], true>
// -> { readonly MacOS: 0, readonly Windows: 1, readonly Linux: 2 }
liangchengv commented 1 year ago
type GetIndex<T extends readonly unknown[]> = T extends readonly [infer R, ...infer I]
? GetIndex<I> | I['length']
: never

type Enum<T extends readonly string[], U = false> = {
   readonly [K in GetIndex<T> as Capitalize<T[K]>]: U extends true ? K : T[K]
}
Naparte commented 1 year ago

type TupleKeys<T extends readonly any[]> = T extends readonly [infer R, ...infer args]
    ? TupleKeys<args> | args['length']
    : never

type MyEumn<T extends readonly any[], bol = false> = {
    readonly [key in TupleKeys<T> as Capitalize<T[key]>]: bol extends false ? T[key] : key
}

// type MyEumn<T extends readonly any[]> = {
//     [K in keyof T[number]]: {
//         [P in keyof T]: P extends K ? P : never
//     }[number]
// }

const OperatingSystem = ['macOS', 'Windows', 'Linux'] as const

type result9 = MyEumn<typeof OperatingSystem>
wudu8 commented 1 year ago
type TupleKeys<T extends readonly any[]> = T extends readonly [infer R, ...infer args] ? TupleKeys<args> | args["length"] : never;

type MyEumn<T extends readonly any[], bol = false> = {
    readonly [key in TupleKeys<T> as T[key]]: bol extends false ? T[key] : key;
};

const OperatingSystem = ["macOS", "Windows", "Linux"] as const;

type keyEnum = MyEumn<["macOS", "Windows", "Linux"]>;
type numberEnum = MyEumn<["macOS", "Windows", "Linux"], true>;
type result9 = MyEumn<typeof OperatingSystem>;
type result10 = MyEumn<typeof OperatingSystem, true>;