Programing

Typescript 유형 '문자열'은 유형에 할당 할 수 없습니다.

lottogame 2020. 9. 11. 19:26
반응형

Typescript 유형 '문자열'은 유형에 할당 할 수 없습니다.


다음은 fruit.ts에있는 것입니다.

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

이제 다른 typescript 파일에서 fruit.ts를 가져옵니다. 여기에 내가 가진 것

myString:string = "Banana";

myFruit:Fruit = myString;

내가 할 때

myFruit = myString;

오류가 발생합니다.

'문자열'유형은 ' "주황색"유형에 할당 할 수 없습니다. | "애플"| "바나나"'

사용자 지정 유형 Fruit의 변수에 문자열을 할당하려면 어떻게해야합니까?


당신은해야합니다 캐스팅 :

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

let myFruit: Fruit = myString as Fruit;

또한 문자열 리터럴 을 사용할 때는 하나만 사용해야합니다.|


Typescript 3.4는 새로운 'const'주장을 소개합니다.

이제 리터럴 유형 (예 : 'orange'또는 'red')이 string소위 const어설 션을 사용 하여 유형으로 '확장'되는 것을 방지 할 수 있습니다 .

다음을 수행 할 수 있습니다.

let fruit = 'orange' as const;

그리고 그것은 string더 이상 스스로가되지 않을 것입니다 . 이것이 질문의 오류의 근원입니다.


이렇게하면 :

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"는 IS 유형 . 확장 String되므로에 할당 할 수 String있습니다. 또한 유형 구성 요소를 확장 때 Union 유형을 확장 합니다 . 이 경우 "Banana"유형 인은 "Orange" | "Apple" | "Banana"해당 구성 요소 중 하나를 확장 하므로 확장됩니다. 따라서, "Banana"귀속이다 "Orange" | "Apple" | "Banana"Fruit.


조금 오래되었지만 여기에 더 나은 해결책이있을 수 있습니다.

문자열을 원하지만 문자열이 특정 값과 만 일치하도록하려면 enums 를 사용할 수 있습니다 .

예를 들면 :

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

let myFruit: Fruit = Fruit.Banana;

Now you'll know that no matter what, myFruit will always be the string "Banana" (Or whatever other enumerable value you choose). This is useful for many things, whether it be grouping similar values like this, or mapping user-friendly values to machine-friendly values, all while enforcing and restricting the values the compiler will allow.


There are several situations that will give you this particular error. In the case of the OP there was a value defined explicitly as a string. So I have to assume that maybe this came from a dropdown, or web service or raw JSON string.

In that case a simple cast <Fruit> fruitString or fruitString as Fruit is the only solution (see other answers). You wouldn't ever be able to improve on this at compile time. [Edit: See my other answer about <const>] !

However it's very easy to run into this same error when using constants in your code that aren't ever intended to be of type string. My answer focuses on that second scenario:


First of all: Why are 'magic' string constants often better than an enum?

  • I like the way a string constant looks vs. an enum - it's compact and 'javascripty'
  • Makes more sense if the component you're using already uses string constants.
  • Having to import an 'enum type' just to get an enumeration value can be troublesome in itself
  • Whatever I do I want it to be compile safe so if I add remove a valid value from the union type, or mistype it then it MUST give a compile error.

Fortunately when you define:

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

...you're actually defining a union of types where 'missing' is actually a type!

I often run into the 'not assignable' error if I have a string like 'banana' in my typescript and the compiler thinks I meant it as a string, whereas I really wanted it to be of type banana. How smart the compiler is able to be will depend on the structure of your code.

Here's an example of when I got this error today:

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

As soon as I found out that 'invalid' or 'banana' could be either a type or a string I realized I could just assert a string into that type. Essentially cast it to itself, and tell the compiler no I don't want this to be a string!

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

So what's wrong with just 'casting' to FieldErrorType (or Fruit)

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

It's not compile time safe:

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

Why? This is typescript so <FieldErrorType> is an assertion and you are telling the compiler a dog is a FieldErrorType! And the compiler will allow it!

BUT if you do the following, then the compiler will convert the string to a type

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

Just watch out for stupid typos like this:

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

Another way to solve the problem is by casting the parent object:

My definitions were as follows:

export type FieldName = 'number' | 'expirationDate' | 'cvv'; export type FieldError = 'none' | 'missing' | 'invalid'; export type FieldErrorType = { field: FieldName, error: FieldError };

Let's say we get an error with this (the string not assignable error):

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

We can 'assert' the whole object as a FieldErrorType like this:

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

Then we avoid having to do <'invalid'> 'invalid'.

But what about typos? Doesn't <FieldErrorType> just assert whatever is on the right to be of that type. Not in this case - fortunately the compiler WILL complain if you do this, because it's clever enough to know it's impossible:

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

If you're casting to a dropdownvalue[] when mocking data for example, compose it as an array of objects with value and display properties.

example:

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

I was facing the same issue, I made below changes and the issue got resolved.

Open watchQueryOptions.d.ts file

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

Change the query type any instead of DocumentNode, Same for mutation

Before:

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

After:

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

참고URL : https://stackoverflow.com/questions/37978528/typescript-type-string-is-not-assignable-to-type

반응형