Подтвердить что ты не робот

Typescript Тип 'string' не присваивается типу

Вот что я имею в fruit.ts

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

Теперь я импортирую файл fruit.ts в другой файл typescript. Вот что я имею

myString:string = "Banana";

myFruit:Fruit = myString;

Когда я делаю

myFruit = myString;

Я получаю сообщение об ошибке:

Тип "строка" не присваивается типу "Оранжевый" | "Яблоко" | "Банан"

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

4b9b3361

Ответ 1

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

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

let myFruit: Fruit = myString as Fruit;

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

Изменить

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

let fruit = "Banana" as const;

Ответ 2

Машинопись 3.4 представляет новое утверждение const

Теперь вы можете предотвратить "расширение" литеральных типов (например, 'orange' или 'red') до типа string с помощью так называемого утверждения const.

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

let fruit = 'orange' as const;

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

Ответ 3

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

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

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

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

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

const myString = "Banana";

const myFruit: Fruit = myString;

...оно работает. Зачем? Поскольку фактический тип myString в этом примере - "Banana". Да, "Banana" это тип. Он расширяет String поэтому его можно назначить String. Кроме того, тип расширяет тип объединения, когда он расширяет любой из его компонентов. В данном случае "Banana", типа, расширяет "Orange" | "Apple" | "Banana" "Orange" | "Apple" | "Banana" "Orange" | "Apple" | "Banana" потому что он расширяет один из своих компонентов. Следовательно, "Banana" назначается на "Orange" | "Apple" | "Banana" "Orange" | "Apple" | "Banana" "Orange" | "Apple" | "Banana" или Fruit.

Ответ 4

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

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

Например:

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

let myFruit: Fruit = Fruit.Banana;

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

Ответ 5

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

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

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


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

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

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

export type FieldErrorType = 'none' | 'missing' | 'invalid'

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

Я часто сталкиваюсь с ошибкой "не присваивается", если в моем наборе текста есть строка типа 'banana' и компилятор считает, что я имел в виду ее как строку, тогда как я действительно хотел, чтобы она была типа 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: <FieldErrorType> 'invalid' } ]

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

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

Зачем? Это машинопись, поэтому <FieldErrorType> является утверждением, и вы говорите компилятору, что собака - это 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 = 'число' | 'expirationDate' | 'CVV'; тип экспорта FieldError = 'none' | "отсутствует" | 'недействительным'; тип экспорта FieldErrorType = {field: FieldName, ошибка: FieldError};

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

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

Мы можем "утверждать" весь объект как FieldErrorType следующим образом:

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

Тогда мы избегаем необходимости делать <'invalid'> 'invalid'.

Но как насчет опечаток? Разве <FieldErrorType> не утверждает только то, что имеет право быть такого типа. Не в этом случае - к счастью, компилятор будет жаловаться, если вы сделаете это, потому что он достаточно умен, чтобы знать, что это невозможно:

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

Ответ 6

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

пример:

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

Ответ 7

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

Откройте файл watchQueryOptions.d.ts

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

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

Перед тем:

export interface QueryBaseOptions<TVariables = OperationVariables> {
    query: **DocumentNode**;

После:

export interface QueryBaseOptions<TVariables = OperationVariables> {
    query: **any**;