Typescript Тип 'string' не может быть назначен типу

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

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

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

myString:string = "Banana";

myFruit:Fruit = myString;

Когда я делаю

myFruit = myString;

Я получаю ошибку:

Тип 'string' нельзя назначить типу "" Orange "| "Яблоко" | "Банан"'

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

 user612372322 июн. 2016 г., 23:34
@WeatherVane Только что проверил мои Fruit.ts. У меня есть одинарные кавычки для типа экспорта Fruit = 'Orange' || «Яблоко» || «Банан». Спасибо
 Weather Vane22 июн. 2016 г., 23:35
Все еще выглядит как двойные кавычки для меня ...
 Weather Vane22 июн. 2016 г., 23:32
Вы абсолютно уверены в использовании одинарных и двойных кавычек вexport type Fruit?

Ответы на вопрос(4)

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

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

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

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

Мне нравится, как выглядит строковая константа по сравнению с 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' } ]
 Simon_Weaver25 янв. 2019 г., 19:10
Могут быть тонкости со строгим режимом. Обновлю ответ после подтверждения.

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

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

... вы создаете тип с именемFruit который может содержать только литералы"Orange", "Apple" а также"Banana", Этот тип расширяетсяStringследовательно, его можно назначитьString, Тем не мение,String НЕ распространяется"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" потому что он расширяет один из своих компонентов. Следовательно,"Banana" присваивается"Orange" | "Apple" | "Banana" или жеFruit.

 Simon_Weaver18 июл. 2019 г., 09:57
Но теперь вы можете сделать<const> 'Banana' что лучше :-)
 Simon_Weaver15 дек. 2018 г., 02:56
Это смешно<'Banana'> 'Banana' и это «бросит»"Banana" строка в"Banana" тип !!!
Решение Вопроса

Вам нужно будетбрось это:

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

let myFruit: Fruit = myString as Fruit;

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

 Nitzan Tomer17 дек. 2018 г., 11:25
@ Сирадж Это должно работать очень хорошо, вам даже не нужноas string часть. Я пробовал твой код на детской площадке и ошибок нет.
 Jacka04 авг. 2017 г., 10:16
хороший :) в большинстве случаевconst myFruit: Fruit = "Banana" сделал бы.
 Siraj Alam17 дек. 2018 г., 11:19
Могу ли я сделать его наоборот? Я имею в виду что-то вроде этогоlet myFruit:Fruit = "Apple" let something:string = myFruit as string   Это дает мне ошибку: преобразование типа 'Fruit' в тип 'string' может быть ошибкой.
 Siraj Alam17 дек. 2018 г., 11:26
@NitzanTomerstackoverflow.com/questions/53813188/... Пожалуйста, посмотрите на мой подробный вопрос

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

Например:

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

let myFruit: Fruit = Fruit.Banana;

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

 Simon_Weaver15 дек. 2018 г., 02:54
Забавно, потому что я получаю эту проблему, пытаясь уйти от этого. Это все больше сводит меня с ума. Я пытаюсь быть «javascripty» и использую магические строки, ограниченные типом (вместо перечисления), и это, кажется, вызывает все больше и больше негативных последствий и пронизывает все мое приложение с этой ошибкой: - /

Ваш ответ на вопрос