Typescript: Создание типов из значений в массиве

Созданный на 22 окт. 2018  ·  16Комментарии  ·  Источник: microsoft/TypeScript


Версия TypeScript: 3.0.3


Условия поиска: тип на основе значений в массиве

Есть ли текущая или планируемая функция для создания типа из строк в массиве?

Код

const values = ['A', 'B']
type Foo = OneOf<values> // Is there a way of doing this?

const v1: Foo = 'A' // This should work
const v2: Foo = 'D' // This should give me an error since 'D' doesn't exist in values

Аналогично тому, как работает keyof :

const values = {
  A: 'A',
  B: 'B'
}
type Foo = keyof typeof values
const v1: Foo = 'A'
const v2: Foo = 'D' // Type '"D"' is not assignable to type '"A" | "B"'

Связанные вопросы:https://github.com/Microsoft/TypeScript/issues/20965

Ссылка на игровую площадку http://www.typescriptlang.org/play/#src = let% 20vals1% 20% 3D% 20% 5B'A '% 2C% 20'B'% 5D% 0D% 0Atype% 20Foo1% 20% 3D% 20OneOf% 3Cvals1% 3E% 20% 2F% 2F% 20Is% 20there% 20a% 20way% 20of% 20doing% 20this% 3F% 0D% 0A% 0D% 0Alet% 20v1% 3A% 20Foo1% 20% 3D% 20 ' A '% 20% 2F% 2F% 20Это% 20 должно% 20work% 0D% 0Alet% 20v2% 3A% 20Foo1% 20% 3D% 20'D'% 20% 2F% 2F% 20Это% 20 должно% 20give% 20me% 20an% 20 error% 20, поскольку% 20'D '% 20 не существует% 20exist% 20in% 20values% 0D% 0A% 0D% 0Alet% 20values2% 20% 3D% 20% 7B% 0D% 0A% 20% 20A% 3A% 20'A '% 2C% 0D% 0A% 20% 20B% 3A% 20'B'% 0D% 0A% 7D% 0D% 0Atype% 20Foo2% 20% 3D% 20keyof% 20typeof% 20vals2% 0D% 0Alet% 20v3% 3A% 20Foo2 % 20% 3D% 20'A '% 0D% 0Alet% 20v4% 3A% 20Foo2% 20% 3D% 20'D'% 20% 2F% 2F% 20Type% 20 '% 22D% 22'% 20is% 20not% 20 назначается % 20to% 20тип% 20 '% 22A% 22% 20% 7C% 20% 22B% 22'

Question

Самый полезный комментарий

в [email protected] и выше. реши это так

export const type = <const>[
  'room',
  'room_with_gifter',
  'user_send'
];

export interface Activity {
  id?: string;
  type: typeof type[number];
}

Все 16 Комментарий

keyof работает только потому, что использует информацию, известную статически во время компиляции. Типы в TS полностью стираются и не существуют в транслируемом коде, поэтому просто невозможно создать тип, основанный на содержимом массива во время выполнения.

Это возможно:

function stringLiterals<T extends string>(...args: T[]): T[] { return args; }
type ElementType<T extends ReadonlyArray<unknown>> = T extends ReadonlyArray<infer ElementType> ? ElementType : never;

const values = stringLiterals('A', 'B');
type Foo = ElementType<typeof values>;

const v1: Foo = 'A' // This should work
const v2: Foo = 'D' // This should give me an error since 'D' doesn't exist in values

Хотя точно не понятно, как это сделать. # 27179 имеет отношение.

Тем не менее, он по-прежнему использует информацию, статически известную компилятору; в этот момент я не понимаю, в чем преимущество простого слова ”A” | “B” .

@fatcerberus Полезно избегать повторения информации - если вы просто напишете const values = ["A", "B"]; type Foo = "A" | "B"; , кто-то может легко изменить одну из них, забыв изменить другую. Вы можете написать const values: Foo[] =["A", "B"]; , но это все равно может добавить дополнительную запись к Foo и забыть поместить ее в values .

Где мы сейчас находимся?

Как сказал @andy-ms, было бы действительно полезно избегать повторения информации вручную.
И, как сказал @fatcerberus , типы полностью стираются. Иногда нам нужно проверять данные во время выполнения, которые мы получаем, например, из не чистой части приложения (например, веб-службы или от пользователя).

Основываясь на ответе @andy-ms и используя утверждения const, представленные в typescript 3.4, теперь можно сделать что-то вроде этого

const values = ['A', 'B'] as const
type ElementType < T extends ReadonlyArray < unknown > > = T extends ReadonlyArray<
  infer ElementType
>
  ? ElementType
  : never

type Foo = ElementType<typeof values> // this is correctly inferred as literal "A" | "B"

Эта проблема была помечена как "Вопрос" и в последнее время не наблюдалась. Он был автоматически закрыт на хозяйственные нужды. Если вы все еще ждете ответа, вопросы обычно лучше подходят для stackoverflow .

в [email protected] и выше. реши это так

export const type = <const>[
  'room',
  'room_with_gifter',
  'user_send'
];

export interface Activity {
  id?: string;
  type: typeof type[number];
}

Вместо этого:

export const items = <const>[
  'room',
  'room_with_gifter',
  'user_send'
];

export interface Activity {
  id?: string;
  type: typeof items[number];
}

Ты можешь это сделать:

export const items = [
  'room',
  'room_with_gifter',
  'user_send'
] as const;

export type Item = typeof items;

export interface Activity {
  id?: string;
  type: Item;
}

image

_ Очень не нравится использовать type в качестве имени переменной. _

@ 7 км

в [email protected] и выше. реши это так

export const type = <const>[
  'room',
  'room_with_gifter',
  'user_send'
];

export interface Activity {
  id?: string;
  type: typeof type[number];
}

Что, если это будет у меня в классе?

class Class {
  const list = <const>[
   'room',
   'room_with_gifter',
   'user_send'
 ];

 const withType: typeof list[number];
}

Не работает. Я тоже не умею делать this.list[number] . Кроме того, для моей конкретной
usecase, я не могу установить list равным static

@ 7 км

в [email protected] и выше. реши это так

export const type = <const>[
  'room',
  'room_with_gifter',
  'user_send'
];

export interface Activity {
  id?: string;
  type: typeof type[number];
}

Что, если это будет у меня в классе?

class Class {
  const list = <const>[
   'room',
   'room_with_gifter',
   'user_send'
 ];

 const withType: typeof list[number];
}

Не работает. Я тоже не умею делать this.list[number] . Кроме того, для моей конкретной
usecase, я не могу установить list равным static

@vegerot Вы не можете использовать const непосредственно в области действия class , поэтому синтаксис неверен.

@ 7 км

в [email protected] и выше. реши это так

export const type = <const>[
  'room',
  'room_with_gifter',
  'user_send'
];

export interface Activity {
  id?: string;
  type: typeof type[number];
}

Что, если это будет у меня в классе?

class Class {
  const list = <const>[
   'room',
   'room_with_gifter',
   'user_send'
 ];

 const withType: typeof list[number];
}

Не работает. Я тоже не умею делать this.list[number] . Кроме того, для моей конкретной
usecase, я не могу установить list равным static

@vegerot Вы не можете использовать const непосредственно в области действия class , поэтому синтаксис неверен.

@ 7kms Моя плохая. Я слишком много копировал и вставлял. Я хотел сказать

class Class {
  private list = <const>[
   'room',
   'room_with_gifter',
   'user_send'
 ];

 private withType: typeof list[number];

// OR
  private withType2: typeof this.list[number];

}

и т.д. все не работает.
Кроме того, для моего конкретного случая использования я не могу сделать список статическим

@ 7 км

в [email protected] и выше. реши это так

export const type = <const>[
  'room',
  'room_with_gifter',
  'user_send'
];

export interface Activity {
  id?: string;
  type: typeof type[number];
}

Что, если это будет у меня в классе?

class Class {
  const list = <const>[
   'room',
   'room_with_gifter',
   'user_send'
 ];

 const withType: typeof list[number];
}

Не работает. Я тоже не умею делать this.list[number] . Кроме того, для моей конкретной
usecase, я не могу установить list равным static

@vegerot Вы не можете использовать const непосредственно в области действия class , поэтому синтаксис неверен.

@ 7kms Моя плохая. Я слишком много копировал и вставлял. Я хотел сказать

class Class {
  private list = <const>[
   'room',
   'room_with_gifter',
   'user_send'
 ];

 private withType: typeof list[number];

// OR
  private withType2: typeof this.list[number];

}

и т.д. все не работает.
Кроме того, для моего конкретного случая использования я не могу сделать список статическим

class Class {
  private list = [
    "room",
    "room_with_gifter",
    "user_send"
  ] as const

  private withType: Class["list"][number]
}

@vegerot Как насчет этого?

@eyalch это typeof или что-то в этом роде. Не могли бы вы быстро объяснить, как это работает, или свяжите меня с руководством, где это обсуждается?

@eyalch это typeof или что-то в этом роде. Не могли бы вы быстро объяснить, как это работает, или свяжите меня с руководством, где это обсуждается?

@vegerot Конечно, я считаю, что это "индексный тип". Вот он в Руководстве: https://www.typescriptlang.org/docs/handbook/advanced-types.html#index -types

Рад, что смог помочь!

Привет,% username%, если решение ElementType не работает и для вас,
обратите внимание на as const после массива . Это важно

Была ли эта страница полезной?
0 / 5 - 0 рейтинги