Array exaustivo TypeScript que contém todas as propriedades de um determinado enum
Eu tenho um enum em TypeScript.
Quero escrever uma função que retorne um array exaustivo que contenha exatamente uma referência a cada propriedade do enum.
O retorno da função será um Array<{ id: EnumValue, label: string }>.
Código de exemplo:
// I have this enum:
enum StepId {
STEP_ONE = 'step-one-id',
STEP_TWO = 'step-two-id',
}
// I want to define some function...
function someFunc() {
return ...
}
// which returns an Array where every value from `StepId` is represented as an object with that value as the `id` field.
someFunc() === [
{ id: CustomStepIds.STEP_ONE, label: 'Step One', },
{ id: CustomStepIds.STEP_TWO, label: 'Step Two', },
];
Eu tentei primeiro resolver o problema de garantir que todos os valores do enum estejam representados em um array. Eu tentei isto:
enum CustomStepId {
STEP_ONE = 'step-one-id',
STEP_TWO = 'step-two-id',
}
type ValueOf<T> = T[keyof T];
const stepConfig: Array<{ id: ValueOf<typeof CustomStepId>, label: string }> = [
{ id: CustomStepId.STEP_ONE, label: 'Step One', },
{ id: CustomStepId.STEP_TWO, label: 'Step Two', },
{ id: CustomStepId.STEP_TWO, label: 'Step Two', }, // this should error, as STEP_TWO is already defined
];
No entanto, como observado no comentário acima, embora isso imponha que id seja um CustomStepId, não garante a unicidade do campo.
Resposta #1
Proponho o seguinte, com base no fato de que eu (e grande parte do mundo TypeScript) evitamos Enums em favor de arrays const. Veja o playground do TypeScript
Eu elaborei mecanismos com base em um mapa ou em uma tupla, dependendo do que você prefere ou precisa.
type MemberOf<Arr extends readonly unknown[]> = Arr[number]
const STEP_IDS = ['step-one-id', 'step-two-id'] as const;
type StepId = MemberOf<typeof STEP_IDS>;
type StepConfigMap = {[k in StepId]: {
label:string
}}
type ConfigTuple<Tuple extends readonly [...unknown[]]> = {
[Index in keyof Tuple]: {
id:Tuple[Index],
label:string
};
} & {length: Tuple['length']};
type StepConfigTuple = ConfigTuple<typeof STEP_IDS>;
const CONFIG_MAP: StepConfigMap = {
"step-one-id":{
label:"something"
},
"step-two-id":{
label:"something else"
},
// errors as it's already defined
// An object literal cannot have multiple properties with the same name.(1117)
"step-two-id":{
label:"something else"
}
} as const;
const CONFIG_TUPLE = [
{
id:"step-one-id",
label:"something",
},
{
id:"step-two-id",
label:"something",
},
// errors as it's already defined
// Source has 3 element(s) but target allows only 2.
{
id:"step-two-id",
label:"something",
}
] as const satisfies StepConfigTuple;
