web-dev-qa-db-ja.com

Typescript型 'string'は型に代入できません

以下は、fruit.tsにあるものです。

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

今、別のTypeScriptファイルにfruit.tsをインポートしています。これが私が持っているものです

myString:string = "Banana";

myFruit:Fruit = myString;

私がする時

myFruit = myString;

エラーが発生します:

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

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

64
user6123723

キャストする

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

let myFruit: Fruit = myString as Fruit;

また、 string literals を使用する場合は、|を1つだけ使用する必要があることに注意してください。

104
Nitzan Tomer

これを行うとき:

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

...リテラル"Orange""Apple"、および"Banana"のみを含むことができるFruitという型を作成しています。この型はStringを拡張するため、Stringに割り当てることができます。ただし、String"Orange" | "Apple" | "Banana"を拡張しないため、それに割り当てることはできません。 Stringより具体的ではないです。 任意の文字列にできます。

これを行うとき:

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

const myString = "Banana";

const myFruit: Fruit = myString;

...できます。どうして?この例のmyStringの実際のtype"Banana"であるためです。はい、"Banana"typeです。 Stringを拡張しているため、Stringに割り当てることができます。さらに、タイプextendsは、コンポーネントのanyを拡張するときのUnion Typeこの場合、タイプの"Banana"は、そのコンポーネントの1つを拡張するため、"Orange" | "Apple" | "Banana"を拡張します。したがって、"Banana""Orange" | "Apple" | "Banana"またはFruitに割り当てることができます。

14
André Pena

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

文字列が必要であるが、特定の値にのみ一致させる場合は、 enums を使用できます。

例えば:

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

let myFruit: Fruit = Fruit.Banana;

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

9
Steve Adams

TypeScript 3.4 は新しい「const」アサーションを導入します

いわゆるstringアサーションを使用して、リテラル型('orange'または'red'など)がconstを入力するように「拡大」されるのを防ぐことができます。

次のことができるようになります。

let fruit = <const> 'orange';

そして、それ自体はstringになりません-これは問題のエラーの根本です。

8
Simon_Weaver

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

その場合、単純なキャスト<Fruit> fruitStringまたはfruitString as Fruitが唯一の解決策です(他の回答を参照)。コンパイル時にこれを改善することはできません。

ただし、コードで定数を使用するときに、同じエラーに遭遇するのは非常に簡単ですこれまで文字列型にするつもりはなかった。私の答えは、2番目のシナリオに焦点を当てています。


まず第一に:「マジック」文字列定数が列挙型よりも優れているのはなぜですか

  • 文字列定数が列挙型に対して見える方法が好きです-コンパクトで「javascripty」です
  • 使用しているコンポーネントがすでに文字列定数を使用している場合、より意味があります。
  • 列挙値を取得するためだけに「列挙型」をインポートしなければならないこと自体が面倒です
  • compile safeにしたいので、ユニオン型から有効な値を削除したり、タイプミスしたりすると、コンパイルエラーが発生します。

幸いなことに以下を定義するとき:

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

...実際に定義しているのはnion of typesここで'missing'は実際には型です!

TypeScriptとコンパイラに'banana'のような文字列があると、「割り当て不可」エラーに遭遇することがよくありますthinks私はそれを文字列として意図していましたが、実際には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 = {field:FieldName、error:FieldError};

これでエラーが発生したとしましょう(文字列ではない割り当て可能なエラー):

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

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

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

その後、<'invalid'> 'invalid'を行う必要がなくなります。

しかし、タイプミスはどうですか? <FieldErrorType>は、そのタイプになる権利があるものは何でもassertしません。この場合ではありません-幸いにも、コンパイラWILLこれを行うと文句を言います。

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

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

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

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

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**;
0
Anand N