web-dev-qa-db-fra.com

Le type de type 'chaîne' n'est pas assignable à un type

Voici ce que j'ai dans fruit.ts

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

Maintenant, j'importe Fruit.ts dans un autre fichier TypeScript. Voici ce que j'ai

myString:string = "Banana";

myFruit:Fruit = myString;

Quand je fais

myFruit = myString;

Je reçois une erreur:

Le type 'chaîne' n'est pas assignable au type '"Orange" | "Apple" | "Banane"'

Comment attribuer une chaîne à une variable de type personnalisé Fruit?

81
user6123723

Vous aurez besoin de le jeter :

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

let myFruit: Fruit = myString as Fruit;

Notez également que lorsque vous utilisez littéraux de chaîne , vous ne devez utiliser qu'un seul |

119
Nitzan Tomer

Quand tu fais ça:

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

... vous créez un type appelé Fruit qui ne peut contenir que les littéraux "Orange", "Apple" et "Banana". Ce type étend String, il peut donc être affecté à String. Cependant, String ne prolonge pas "Orange" | "Apple" | "Banana", et ne peut donc pas lui être attribué. String est moins spécifique. Cela peut être n'importe quelle chaîne.

Quand tu fais ça:

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

const myString = "Banana";

const myFruit: Fruit = myString;

...Ça marche. Pourquoi? Parce que le type de myString dans cet exemple est "Banana". Oui, "Banana" est le type. Il est étendu String donc il est assignable à String. En outre, un type étend un type d'union lorsqu'il étend tout de ses composants. Dans ce cas, "Banana", le type, étend "Orange" | "Apple" | "Banana" car il étend l'un de ses composants. Par conséquent, "Banana" est assignable à "Orange" | "Apple" | "Banana" ou Fruit.

17
André Pena

TypeScript 3.4 introduit la nouvelle assertion 'const'

Vous pouvez maintenant empêcher les types littéraux (par exemple, _'orange'_ ou _'red'_) d'être élargis pour taper string avec une assertion dite const.

Vous pourrez faire:

_let fruit = <const> 'orange';
_

Et puis cela ne se transformera plus en une string - qui est la racine de l'erreur dans la question.

14
Simon_Weaver

Je vois que c'est un peu vieux, mais il pourrait y avoir une meilleure solution ici.

Lorsque vous voulez une chaîne, mais que vous voulez que la chaîne ne corresponde qu'à certaines valeurs, vous pouvez utiliser enums .

Par exemple:

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

let myFruit: Fruit = Fruit.Banana;

Maintenant, vous saurez que quoi qu'il en soit, myFruit sera toujours la chaîne "Banana" (ou toute autre valeur énumérable que vous choisissez). Ceci est utile pour beaucoup de choses, qu'il s'agisse de grouper des valeurs similaires, ou de mapper des valeurs conviviales à des valeurs conviviales, tout en appliquant et en restreignant les valeurs autorisées par le compilateur.

10
Steve Adams

Il existe plusieurs situations qui vous donneront cette erreur particulière. Dans le cas du PO, il y avait une valeur définie explicitement comme une chaîne. Je suppose donc que cela provient peut-être d'un menu déroulant, d'un service Web ou d'une chaîne JSON brute.

Dans ce cas, une simple conversion <Fruit> fruitString ou fruitString as Fruit est la seule solution (voir les autres réponses). Vous ne pourrez jamais améliorer cela au moment de la compilation. [ Edit: Voir mon autre réponse à propos de <const>]!

Cependant, il est très facile de rencontrer la même erreur lorsque vous utilisez des constantes dans votre code qui ne sont jamais destinées à être de type string. Ma réponse se concentre sur ce deuxième scénario:


Tout d’abord: Pourquoi les constantes de chaîne 'magiques' sont-elles souvent meilleures qu’une énumération?

  • J'aime l'apparence d'une constante de chaîne par rapport à une énumération: sa compacité et son "javascript"
  • Plus utile si le composant que vous utilisez utilise déjà des constantes de chaîne.
  • Devoir importer un 'type enum' juste pour obtenir une valeur d'énumération peut être gênant en soi
  • Quoi que je fasse, je veux que ce soit sécurité de la compilation donc si j'ajoute une valeur valide du type d'union, ou si elle est erronée, elle DOIT donner une erreur de compilation.

Heureusement quand vous définissez:

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

... vous définissez en fait un nion de types'missing' est en fait un type!

Je rencontre souvent l'erreur 'not assignable' si j'ai une chaîne de caractères telle que 'banana' dans mon TypeScript et le compilateur pense je le pensais sous la forme d'une chaîne de caractères, alors que je le voulais vraiment tapez banana. L'intelligence du compilateur dépendra de la structure de votre code.

Voici un exemple de quand j'ai eu cette erreur aujourd'hui:

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

Dès que j'ai découvert que 'invalid' ou 'banana' pouvait être un type ou une chaîne, j'ai réalisé que je pouvais simplement affirmer une chaîne dans ce type. Essentiellement le jette sur lui-même, et dit au compilateur non, je ne veux pas que ce soit une chaîne!

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

Alors, qu'est-ce qui ne va pas avec le "casting" de FieldErrorType (ou Fruit)

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

Ce n'est pas sûr de compiler le temps:

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

Pourquoi? Il s'agit de TypeScript donc <FieldErrorType> est une assertion et vous indiquez au compilateur qu'un chien est un FieldErrorType! Et le compilateur le permettra!

MAIS si vous procédez comme suit, le compilateur convertira la chaîne en un type

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

Faites juste attention aux fautes de frappe stupides comme ceci:

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

Un autre moyen de résoudre le problème consiste à convertir l'objet parent:

Mes définitions étaient les suivantes:

type d'exportation FieldName = 'nombre' | 'expirationDate' | 'cvv'; type d'exportation FieldError = 'none' | 'manquant' | 'invalide'; type d'exportation FieldErrorType = {field: FieldName, error: FieldError};

Disons que nous obtenons une erreur avec ceci (la chaîne d'erreur non assignable):

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

Nous pouvons 'affirmer' l'objet entier comme un FieldErrorType comme ceci:

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

Ensuite, nous évitons de devoir faire <'invalid'> 'invalid'.

Mais qu'en est-il des fautes de frappe? <FieldErrorType> ne fait pas affirmer tout ce qui est à droite pour être de ce type. Pas dans ce cas - heureusement, le compilateur VA se plaindra si vous faites cela, car il est assez malin pour savoir que c'est impossible:

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

Si vous transformez un dropdownvalue[] lors du mocking de données, par exemple, composez-le comme un tableau d'objets avec des propriétés value et display.

exemple:

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

Je faisais face au même problème, j'ai apporté les modifications ci-dessous et le problème a été résolu.

Ouvrez le fichier watchQueryOptions.d.ts

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

Changer le type de requête any au lieu de DocumentNode, idem pour mutation

Avant:

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

Après:

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