Typescriptタイプ 'string'はタイプに割り当て可能ではありません


161

これが私がfruit.tsに持っているものです

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

今度は別のtypescriptファイルでfruit.tsをインポートしています。ここに私が持っているものがあります

myString:string = "Banana";

myFruit:Fruit = myString;

私がする時

myFruit = myString;

エラーが発生します:

タイプ 'string'はタイプ '"Orange"に割り当てることができません| 「アップル」| "バナナ"'

カスタム型Fruitの変数に文字列を割り当てるにはどうすればよいですか?


1
での単一引用符と二重引用符の使用について、本当に確信がありますexport type Fruitか?
Weather Vane

1
@WeatherVaneちょうど私のFruit.tsをチェックしました。エクスポートタイプFruit = 'Orange'の単一引用符があります|| 「リンゴ」||「バナナ」。ありがとう
user6123723

まだ二重引用符のように見えます...
Weather Vane

回答:


231

キャストする必要があります:

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

let myFruit: Fruit = myString as Fruit;

また、文字列リテラルを使用する場合は、1つだけ使用する必要があることに注意してください。|

編集する

@Simon_Weaverによる他の回答で述べたように、次のようにアサートすることが可能になりましたconst

let fruit = "Banana" as const;

11
素敵な1つ:)ほとんどの場合const myFruit: Fruit = "Banana"
ジャッカ2017

その逆はできますか?私はこのようなものを意味します let myFruit:Fruit = "Apple" let something:string = myFruit as string それは私にエラーを与えています:タイプ '果物'からタイプ '文字列'への変換は間違いかもしれません。
シラジアラム2018

@Siraj正常に動作するはずですas string。パーツは必要ありません。私はあなたのコードを遊び場で試しましたが、エラーはありません。
Nitzan Tomer 2018

@NitzanTomer stackoverflow.com/questions/53813188/...私の詳細な質問を見てください
のSirajアラム

しかし、タイプミスし const myString: string = 'Bananaaa'; ても、キャストのためにコンパイルエラーが発生しません...文字列の型チェック中にこれを行う方法はありませんか?
blub

66

Typescript 3.4は新しい 'const'アサーションを導入します

これで、リテラルタイプ(例:'orange'または'red')がstringいわゆる「タイプ」に「拡張」されて、いわゆるconstアサーションを使用して。

あなたができるようになります:

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

そして、それはstringもはやそれ自体に変わることはありません-それが問題の問題の根源です。


私のように、まだ3.4を使っていない人のために。<const>は任意のものに置き換えることができますが、もちろんこのソリューションほどきれいではありません。
Pieter De Bie

2
推奨される構文はlet fruit = 'orange' as const;、no-angle-bracket-type-assertionルール
に従う場合です

2
これが最新のTypescriptの正解です。これにより、不要なタイプのインポートが防止され、構造化タイプ付けが正しく行われます。
ジェームズマクマホン

24

これを行うと:

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です。さらに、型、そのコンポーネントのいずれかを拡張する場合、Union 型を拡張します。この場合、"Banana"タイプで"Orange" | "Apple" | "Banana"あるは、コンポーネントの1つを拡張するために拡張されます。したがって、またはに"Banana"割り当て可能です。"Orange" | "Apple" | "Banana"Fruit


2
それはあなたが実際に置くことができて面白いです<'Banana'> 'Banana'、そしてそれはタイプに"Banana"文字列を「キャスト」します"Banana"!!!
Simon_Weaver 2018

2
しかし、今あなたは<const> 'Banana'どちらが良いかをすることができます:-)
Simon_Weaver

11

これは少し古いと思いますが、もっと良い解決策があるかもしれません。

文字列が必要だが、文字列が特定の値のみに一致するようにしたい場合は、enumを使用できます。

例えば:

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

let myFruit: Fruit = Fruit.Banana;

これで、myFruitは常に文字列 "Banana"(または選択した他の列挙可能な値)になることがわかります。これは、このような類似した値をグループ化する場合でも、ユーザーフレンドリーな値をマシンフレンドリーな値にマッピングする場合でも、コンパイラーが許可する値を適用および制限しながら、多くの場合に役立ちます。


1
これを回避しようとするとこの問題が発生するので、面白いです。それはますます私にナッツを運転しています。私は「列挙」の代わりに「javascripty」になり、型に制約された魔法の文字列を使用しようとしています、それはますますバックファイアし、このエラーでアプリケーション全体に波及しているようです:-/
Simon_Weaver

1
これも逆の問題を引き起こします。あなたはもはやすることができませんlet myFruit: Fruit = "Banana"
Sean Burton、

11

この特定のエラーが発生する状況はいくつかあります。OPの場合、文字列として明示的に定義された値がありました。そのため、ドロップダウン、Webサービス、または未加工のJSON文字列が原因であると想定する必要があります。

その場合には、単純なキャスト<Fruit> fruitStringfruitString as Fruit(他の回答を参照してください)唯一のソリューションです。コンパイル時にこれを改善することはできません。[ 編集:私の他の回答を参照してください<const> ]!

ただし、string型であることが意図されていないコードで定数を使用すると、この同じエラーが発生するのは非常に簡単です。私の答えは、その2番目のシナリオに焦点を当てています。


まず第一に、なぜ「魔法の」文字列定数はしばしば列挙型よりも優れているのですか?

  • 文字列定数の外観と列挙型の違い-コンパクトで「javascripty」
  • 使用しているコンポーネントがすでに文字列定数を使用している場合、より意味があります。
  • 列挙値を取得するためだけに「列挙型」をインポートする必要があることは、それ自体が面倒な場合があります
  • 私が何をしてもそれをコンパイルセーフにしたいので、追加してユニオンタイプから有効な値を削除したり、タイプミスしたりすると、コンパイルエラーが発生するはずです。

幸いにも次のように定義すると:

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!

どうして?これはtypescriptなので<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 = 'number' | 'expirationDate' | 'cvv'; エクスポートタイプFieldError = 'none' | '行方不明' | '無効'; エクスポートタイプFieldErrorType = {フィールド:FieldName、エラー:FieldError};

これでエラーが発生したとしましょう(文字列not assignableエラー):

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

オブジェクト全体を次のFieldErrorTypeように「アサート」できます。

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

その後、私たちはやらなければならないことを避けます<'invalid'> 'invalid'

しかし、タイプミスはどうですか?そのタイプであることの右側にあるものを主張する<FieldErrorType>だけではありません。このケースではない-幸いコンパイラはWILLあなたがこれを行う場合、それはそれは不可能だ知っている賢い十分なので、文句を言います:

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

ストリクトモードでは微妙な問題が発生する可能性があります。確認後、回答を更新します。
Simon_Weaver

1

上記の答えはすべて有効ですが、文字列リテラル型が別の複合型の一部である場合があります。次の例を検討してください。

  // 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)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)
  ));

0

dropdownvalue[]たとえば、データをモックするときににキャストする場合は、値と表示プロパティを持つオブジェクトの配列としてそれを構成します。

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

0

私は同じ問題に直面していました、以下の変更を行い、問題は解決しました。

watchQueryOptions.d.tsファイルを開きます

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

クエリタイプをDocumentNodeの代わりにanyに変更し、ミューテーションについても同じ

前:

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

後:

export interface QueryBaseOptions<TVariables = OperationVariables> {
    query: **any**;
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.