Mam takie is

enum Test {
   'type1',
   'type2',
   'type3',
   'type4',
   'type5'
}

function getType(num: number) {

}

To czego chcę to jeśli num = 1, zwróć type1, jeśli num = 2, zwróć type2, jeśli num >= 5, zwróć type5.

Jak mogę to zrobić w getType ?

1
Nika Kurashvili 5 styczeń 2022, 14:02
2
Co jeśli num to 0? Co jeśli num to 1.2?
 – 
Lesiak
5 styczeń 2022, 14:13
Jeśli zwrócisz Test[0] wewnątrz getType, faktycznie zwróci pierwszy element w wyliczeniu, 1.2 jednak zwróci undefined. Korzystanie z number wymaga dodatkowej ochrony, aby zapewnić zwrócenie prawidłowego elementu wyliczenia.
 – 
Mike S.
5 styczeń 2022, 14:46
@MikeS. Obawiam się, że to tylko założenia, jak funkcja powinna się zachowywać. Nigdy nie powiedziałem, że zamierzam używać indeksatora podczas wdrażania getType
 – 
Lesiak
5 styczeń 2022, 14:54

2 odpowiedzi

Najlepsza odpowiedź

Wyliczenia TypeScript są dostępne, mimo że istnieje indeks numeryczny w czasie wykonywania, więc

return Test[1];

Zwróci indeks 1 z wyliczenia Test.


Ponieważ chcesz, aby 1 zwrócił type1, musimy odjąć 1 od Twojego num, aby uzyskać żądany indeks:

enum Test {
   'type1',
   'type2',
   'type3',
   'type4',
   'type5'
}

function getType(num: number) {
    return Test[num - 1];
}   

console.log(getType(1));

Wyświetli:

type1

Wypróbuj online!

2
0stone0 5 styczeń 2022, 14:10
Ale tutaj zwracany typ to ciąg, a nie Test
 – 
Eldar
5 styczeń 2022, 14:14
Tak, ale jeśli liczba jest większa lub równa 5, powinna zwrócić type5. Chyba powinienem zrobić if(num >= 5) return Test[5] ?
 – 
Nika Kurashvili
5 styczeń 2022, 14:18
Możesz zrobić coś takiego jak return Test[num - 1] || Test[4], aby upewnić się, że istnieje. Proszę zobaczyć w akcji za pomocą to Online demo.
 – 
0stone0
5 styczeń 2022, 14:22

To trudne pytanie. Zobacz powiązane pytanie i moje artykuł.

Reprezentacja enum w czasie wykonywania jest obiektem dwukierunkowym.

const Test = {
  0: "type1",
  1: "type2",
  2: "type3",
  3: "type4",
  4: "type5",
  type1: 0,
  type2: 1,
  type3: 2,
  type4: 3,
  type5: 4,
}

Proszę o tym pamiętać podczas czytania.

Rozważ ten przykład:


enum MyEnum {
  ONE, // 0
  TWO // 1
}

// This utility type reverses object. 
// All keys become values an all values become keys
type ReverseObj<T extends Record<string, string | number>> = {
  [Prop in keyof T as T[Prop]]: Prop
}

{
  type _ = ReverseObj<{ age: 42 }> // { 42: "age" }
}

// Type representation of runtime enum value
// Please keep in mind that enum runtime value is bidirectional
// this is why I have used ReverseObject
type EnumToObj = Pick<
  {
    [Prop in keyof typeof MyEnum]: `${typeof MyEnum[Prop]}`
  }, keyof typeof MyEnum
>

type IsKeyValid<
  InitialValue extends number,
  > =
  `${InitialValue}` extends keyof ReverseObj<EnumToObj>
  ? InitialValue
  : never

{
  type _ = IsKeyValid<1> // 1
  type __ = IsKeyValid<2> // never
}

function handleEnum<
  Index extends number,
  >(index: IsKeyValid<Index>): `${Index}` extends keyof ReverseObj<EnumToObj> ? ReverseObj<EnumToObj>[`${Index}`] : never
function handleEnum<
  Index extends number,
  >(index: IsKeyValid<Index>) {
  return MyEnum[index]
}

handleEnum(0) // "ONE"
handleEnum(1) // "TWO"
handleEnum(2) // expected error
handleEnum('ONE') // expected error
handleEnum(0.1) // expected error
handleEnum(NaN) // expected error
handleEnum(Infinity) // expected error

Plac zabaw

Pewne wyjaśnienie znajdziesz w komentarzach. Celem jest uczynienie nielegalnego państwa niereprezentacyjnym.

IsKeyValid - zapewnia, że ​​nie możesz dostarczać kluczy, które nie istnieją w enum. Na przykład nie możesz zadzwonić do handleEnum(10), ponieważ mamy tylko dwa klucze, stąd dozwolone klucze to 0 | 1. Jeśli chodzi o wartość zwracaną, uzyskałem ją z odwróconego obiektu ReverseObj.

Coś, o czym powinieneś wiedzieć:

  1. Typy typeof MyEnum i MyEnum nie są równe.
  2. Więcej wyjaśnień na temat używania as w [Prop in keyof T as T[Prop]]: Prop znajdziesz tutaj
  3. Warto użyć prostej krotki zamiast enum, jeśli nie używasz niestandardowych początkowych indeksów dla enum. Rozważ ten przykład:
const TUPLE = ['one', 'two', 'three'] as const;

type Tuple = typeof TUPLE

type AllowedIndex<Index extends number> = `${Index}` extends Exclude<keyof Tuple, keyof ReadonlyArray<any>> ? Index : never

const getter = <Index extends number>(index: AllowedIndex<Index>) =>
  TUPLE[index]

getter(1) // ok, returns "two"
getter(23) // expected error
  1. W większości przypadków nawet lepiej jest użyć immutable object zamiast enum.
const FakeEnum = {
  a: 0,
  b: 1
} as const

Praca z obiektem FakeEnum jest łatwa. Bo można łatwo, bez żadnych sztuczek uzyskać klucze i odpowiednio dobrać wartości obiektu.

IMHO, nie sądzę, że enum jest najlepszą opcją do użycia w tym przypadku

PS Jeśli nie lubisz indeksu od zera w wyliczeniach, możesz ustawić swoją początkową wartość:

enum MyEnum {
  ONE = 1, // 1
  TWO // 2
}
3
captain-yossarian 5 styczeń 2022, 15:20