Вот что у меня в fruit.ts

export type Fruit = "Orange" | "Apple" | "Banana"

Сейчас я импортирую fruit.ts в другой машинописный файл. Вот что у меня

myString:string = "Banana";

myFruit:Fruit = myString;

Когда я сделаю

myFruit = myString;

Получаю ошибку:

Тип «строка» не может быть присвоен типу «Оранжевый» | «Яблоко» | «Банан» '

Как присвоить строку переменной произвольного типа Fruit?

user6123723

Ответов: 12

Ответы (12)

Вам нужно будет разыграть:

export type Fruit = "Orange" | "Apple" | "Banana";
let myString: string = "Banana";

let myFruit: Fruit = myString as Fruit;

Также обратите внимание, что при использовании строковых литералов вам нужно использовать только один |

Редактировать

Как упоминалось в другом ответе @Simon_Weaver, теперь можно утверждать его как const:

let fruit = "Banana" as const;

Когда вы это сделаете:

export type Fruit = "Orange" | "Apple" | "Banana"

... вы создаете тип с именем Fruit, который может содержать только литералы "Orange", "Apple" и "Banana «. Этот тип расширяет String, поэтому его можно присвоить String. Однако String НЕ расширяет «Orange» | «Яблоко» | "Банан", поэтому не может быть ему назначен.Строка менее конкретная. Это может быть любая строка.

Когда вы это сделаете:

export type Fruit = "Orange" | "Apple" | "Banana"

const myString = "Banana";

const myFruit: Fruit = myString;

... работает. Почему? Поскольку фактический тип из myString в этом примере это "Banana". Да, "Банан" - это тип . Он расширяет String, поэтому его можно присвоить String. Кроме того, тип расширяет Union Type, когда он расширяет любые его компоненты. В этом случае "Банан", тип расширяет "Апельсин" | «Яблоко» | «Банан», потому что он расширяет один из своих компонентов. Следовательно, "Банан" присваивается "Апельсин" | «Яблоко» | «Банан» или Фруктовый.

У меня была аналогичная проблема при передаче props в компонент React.

Причина: Мой вывод типа на myArray работал некорректно

https://codesandbox.io/s/type-string-issue-fixed-z9jth?file=/ src / App.tsx

Особая благодарность Брэди из Reactiflux за помощь в решении этой проблемы.

Все приведенные выше ответы действительны, однако в некоторых случаях строковый литерал является частью другого сложного типа. Рассмотрим следующий пример:

  // in foo.ts
  export type ToolbarTheme = {
    size: 'large' | 'small',
  };

  // in bar.ts
  import { ToolbarTheme } from './foo.ts';
  function useToolbarTheme(theme: ToolbarTheme) {/* ... */}

  // Here you will get the following error: 
  // Type 'string' is not assignable to type '"small" | "large"'.ts(2322)
  ['large', 'small'].forEach(size => (
    useToolbarTheme({ size })
  ));

У вас есть несколько решений, чтобы исправить это. Каждое решение действительно и имеет свои варианты использования.

1) Первое решение - определить тип для размера и экспортировать его из foo.ts. Это хорошо, если нужно работать с параметром размера самостоятельно. Например, у вас есть функция, которая принимает или возвращает параметр размера типа, и вы хотите его ввести.

  // in foo.ts
  export type ToolbarThemeSize = 'large' | 'small';
  export type ToolbarTheme = {
    size: ToolbarThemeSize
  };

  // in bar.ts
  import { ToolbarTheme, ToolbarThemeSize } from './foo.ts';
  function useToolbarTheme(theme: ToolbarTheme) {/* ... */}
  function getToolbarSize(): ToolbarThemeSize  {/* ... */}

  ['large', 'small'].forEach(size => (
    useToolbarTheme({ size: size as ToolbarThemeSize })
  ));

2) Второй вариант - просто привести его к типу ToolbarTheme. В этом случае вам не нужно открывать внутреннюю часть ToolbarTheme, если она вам не нужна.

  // in foo.ts
  export type ToolbarTheme = {
    size: 'large' | 'small'
  };

  // in bar.ts
  import { ToolbarTheme } from './foo.ts';
  function useToolbarTheme(theme: ToolbarTheme) {/* ... */}

  ['large', 'small'].forEach(size => (
    useToolbarTheme({ size } as ToolbarTheme)
  ));

Typescript 3.4 представил новое утверждение const

Теперь вы можете предотвратить «расширение» литеральных типов (например, 'оранжевый' или 'красный') до типа string с так называемымconst утверждение.

Вы сможете сделать:

let fruit = 'orange' as const;  // or...
let fruit =  'orange';

И тогда он больше не превратится в строку - что является корнем проблемы в вопросе.

Бонусный совет: Вы также можете использовать false или true для представления логического значения, которое должно быть истинным или ложным. Иногда это может быть полезно в дискриминируемых объединениях. Вы поймете это, когда увидите.

Я столкнулся с той же проблемой, я внес изменения ниже, и проблема была решена.

Открыть watchQueryOptions.d.ts файл

\apollo-client\core\watchQueryOptions.d.ts

Изменить тип запроса любой вместо DocumentNode, то же самое для мутации

Раньше:

export interface QueryBaseOptions {
    query: **DocumentNode**;

После:

export interface QueryBaseOptions {
    query: **any**;

Я вижу, что это немного устарело, но здесь может быть лучшее решение.

Если вам нужна строка, но вы хотите, чтобы строка соответствовала только определенным значениям, вы можете использовать перечисления.

Например:

enum Fruit {
    Orange = "Orange",
    Apple  = "Apple",
    Banana = "Banana"
}

let myFruit: Fruit = Fruit.Banana;

Теперь вы будете знать, что, несмотря ни на что, myFruit всегда будет строкой «Banana» (или любым другим перечислимым значением, которое вы выберете). Это полезно для многих вещей, будь то группировка подобных значений, подобная этой, или сопоставление удобных для пользователя значений с машинно-понятными значениями, и все это при обеспечении и ограничении значений, допускаемых компилятором.

Этот вопрос был помечен как Angular, хотя на самом деле он не имеет ничего общего с Angular. Однако есть (по крайней мере) один конкретный случай Angular, когда вы можете неожиданно получить эту ошибку.

  • Если вы отключили strictNullInputTypes
  • Если вы используете буквальный тип, например Fruit как @ Input ()
  • Вы пытаетесь передать 'Orange' на вход, и он интерпретируется как строка.

Это будет исправлено в Angular 13.1.

https://github.com/angular/angular/pull/38305

Я получал то же сообщение об ошибке с немного другим сценарием. Я пришел сюда в поисках ответов, но ни один из ответов у меня не помог, поэтому я поделюсь своим решением с другими. У меня не было специального типа, это был просто массив строк. У меня был объект myObject со строковым свойством abcOrD, которое должно было быть одним из значений в массиве строк, например «a» «b» «c» или «d». При попытке присвоить myObject.abcOrD = myStringVar мне будет выдано сообщение об ошибке Тип «строка» не может быть назначен типу «a» | "б" | "с" | «d». Поигравшись и попробовав некоторые вещи, что сработало для меня, я использовал как любой:

myObject.abcOrD = myStringVar as any;

В массивах с растяжением эту ошибку все же можно выдать немного неверно:

export type Fruit = "Orange" | "Apple" | "Banana"
export type FruitArray = Fruit[];

const someFruits= ["Banana"];

const workingFruits: FruitArray = ["Orange", "Apple"]; // Works

// Even orange and apple show: Type 'string' is not assignable to type Fruit
const brokenAllFruits: FruitArray = [...someFruits, "Orange", "Apple"]; 

// As const is needed in the spread array
const someConstFruits= ["Banana" as const];
const workingAllFruits: FruitArray = [...someConstFruits, "Orange", "Apple"]; // Works

Если вы выполняете приведение к dropdownvalue [] при имитации данных, например, составьте его как массив объектов со значением и свойствами отображения.

пример:

[{'value': 'test1', 'display1': 'test display'},{'value': 'test2', 'display': 'test display2'},]

Есть несколько ситуаций, в которых выдается именно эта ошибка. В случае OP было значение , явно определенное как строка. Поэтому я должен предположить, что, возможно, это произошло из раскрывающегося списка, или веб-службы, или необработанной строки JSON.

В этом случае простое приведение fruitString или fruitString как Fruit является единственным решением (см. Другие ответы). Вы никогда не сможете улучшить это во время компиляции. [Изменить: см. Мой другой ответ о ]!

Однако очень легко столкнуться с той же ошибкой при использовании в вашем коде констант, которые никогда не предназначены для строкового типа. Мой ответ сосредоточен на втором сценарии:


Прежде всего: Почему «магические» строковые константы часто лучше, чем перечисления?

  • Мне нравится, как строковая константа выглядит по сравнению с перечислением - она ​​компактна и 'javascripty'
  • Имеет смысл, если используемый вами компонент уже использует строковые константы.
  • Необходимость импортировать «тип перечисления» только для получения значения перечисления может быть проблемной сама по себе
  • Что бы я ни делал, я хочу, чтобы это было безопасно для компиляции поэтому, если я добавлю удаление допустимого значения из типа объединения или опечатку, оно ДОЛЖНО выдать ошибку компиляции.

К счастью, когда вы определяете:

тип экспорта FieldErrorType = 'none' | «пропал без вести» | 'недопустимый'

... вы на самом деле определяете объединение типов, где 'отсутствует' на самом деле является типом!

Я часто сталкиваюсь с ошибкой «не назначается», если у меня есть строка типа 'banana' в моем машинописном тексте, а компилятор думает Я имел в виду это как строку, тогда как я очень хотел, чтобы он был типа банан. Насколько умным будет компилятор, будет зависеть от структуры вашего кода.

Вот пример того, когда я получил эту ошибку сегодня:

// this gives me the error 'string is not assignable to type FieldErrorType'
fieldErrors: [ { fieldName: 'number', error: 'invalid' } ]

Как только я узнал, что 'invalid' или 'banana' может быть типом или строкой, я понял, что могу просто утверждать строку в этом введите. По сути, приводит его к самому себеи сообщает компилятору нет, я не хочу, чтобы это была строка!

// so this gives no error, and I don't need to import the union type too
fieldErrors: [ { fieldName: 'number', error: <'invalid'> 'invalid' } ]

Так что же плохого в простом преобразовании в FieldErrorType (или Fruit)

// why not do this?
fieldErrors: [ { fieldName: 'number', error:  'invalid' } ]

Это небезопасно во время компиляции:

  'invalidddd';  // COMPILER ALLOWS THIS - NOT GOOD!
  'dog';         // COMPILER ALLOWS THIS - NOT GOOD!
 'dog' as FieldErrorType;        // COMPILER ALLOWS THIS - NOT GOOD!

Почему? Это машинописный текст, поэтому - это утверждение, а вы сообщаете компилятору, что собака - это FieldErrorType! И компилятор это позволит!

НО если вы сделаете следующее, то компилятор преобразует строку в тип

 <'invalid'> 'invalid';     // THIS IS OK  - GOOD
 <'banana'> 'banana';       // THIS IS OK  - GOOD
 <'invalid'> 'invalidddd';  // ERROR       - GOOD
 <'dog'> 'dog';             // ERROR       - GOOD

Только остерегайтесь таких дурацких опечаток:

 <'banana'> 'banan';    // PROBABLY WILL BECOME RUNTIME ERROR - YOUR OWN FAULT!

Другой способ решить проблему - приведение родительского объекта:

Мои определения были такими:

тип экспорта FieldName = 'number' | 'expirationDate' | 'cvv'; тип экспорта FieldError = 'none' | «пропал без вести» | 'недействителен'; тип экспорта FieldErrorType = {field: FieldName, error: FieldError};

Допустим, мы получаем ошибку с этим (строка не назначаемая ошибка):

  fieldErrors: [ { field: 'number', error: 'invalid' } ]

Мы можем «утверждать» весь объект как FieldErrorType вот так:

  fieldErrors: [  { field: 'number', error: 'invalid' } ]

Тогда нам не нужно делать <'invalid'> 'invalid'.

А как быть с опечатками? Не просто утверждает все, что справа, чтобы относиться к этому типу. Не в этом случае - к счастью, компилятор БУДЕТ жаловаться, если вы это сделаете, потому что он достаточно умен, чтобы знать, что это невозможно:

  fieldErrors: [  { field: 'number', error: 'dog' } ]

2022 WebDevInsider