打字稿类型“字符串”不可分配给类型

2020/10/22 09:21 · javascript ·  · 0评论

这是我在fruit.ts中拥有的东西

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

现在,我要在另一个打字稿文件中导入fruit.ts。这就是我所拥有的

myString:string = "Banana";

myFruit:Fruit = myString;

当我做

myFruit = myString;

我收到一个错误:

类型'string'不能分配给类型'“ Orange” | “苹果” | “香蕉”'

如何为自定义类型Fruit的变量分配字符串?

您需要强制转换

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

let myFruit: Fruit = myString as Fruit;

还要注意,使用字符串文字时,您只需要使用一个|

编辑

如@Simon_Weaver的另一个答案中所述,现在可以将其声明为const

let fruit = "Banana" as const;

Typescript3.4引入了新的“ const”断言

现在,您可以防止文字类型(例如'orange''red')被“扩展”为string使用所谓的const断言来键入

您将可以执行以下操作:

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

然后它不会再变成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"类型它是可扩展的,String因此可以分配给String此外,一种扩展,当它延伸的联盟类型的任何其组件。在这种情况下,"Banana"类型会扩展,"Orange" | "Apple" | "Banana"因为它会扩展其组件之一。因此,"Banana"可分配给"Orange" | "Apple" | "Banana"Fruit

我看到这有点旧,但是这里可能有更好的解决方案。

当您需要一个字符串,但又希望该字符串仅匹配某些值时,可以使用enums

例如:

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

let myFruit: Fruit = Fruit.Banana;

现在您将知道,无论如何,myFruit始终是字符串“ Banana”(或您选择的任何其他可枚举值)。这对于许多事情很有用,无论是将类似的值分组,还是将用户友好的值映射到机器友好的值,同时强制和限制编译器将允许的值。

在几种情况下,您会遇到此特定错误。对于OP,有一个明确定义为字符串的值因此,我必须假设这可能来自下拉列表,Web服务或原始JSON字符串。

在那种情况下,简单的强制转换<Fruit> fruitString或是fruitString as Fruit唯一的解决方案(请参阅其他答案)。您将永远无法在编译时对此进行改进。[编辑:查看我关于的其他答案<const>

但是,在代码中使用原本不打算为string类型的常量时,很容易遇到相同的错误我的回答集中在第二种情况:


首先:为什么“魔术”字符串常量通常比枚举更好?

  • 我喜欢字符串常量与枚举的外观-它紧凑且“ javascripty”
  • 如果您正在使用的组件已经使用了字符串常量,则更有意义。
  • 仅为了获取枚举值而必须导入“枚举类型”本身可能很麻烦
  • 无论我做什么,我都希望它是编译安全的,因此,如果我添加从联合类型中删除有效值,或者输入错误的类型,则它必须给出编译错误。

幸运的是,当您定义:

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

...您实际上是在定义类型的集,'missing'实际上是一个类型!

如果'banana'我的打字稿中有一个字符串,并且编译器认为我将其表示为字符串,那么我经常会遇到“无法分配”错误,而我真的希望它是type 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' } ]

以上所有答案都是有效的,但是在某些情况下,字符串文字类型是另一种复杂类型的一部分。考虑以下示例:

  // 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中导出它。如果您需要单独使用size参数,则这很好。例如,您有一个接受或返回类型为size的参数的函数,并且您想键入它。

  // 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)第二种选择是将其强制转换为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)
  ));

dropdownvalue[]例如,如果要在模拟数据时强制转换为a ,请将其组合为具有值和显示属性的对象数组。

例如

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

将道具传递到React组件时,我遇到了类似的问题。

原因: My type inference on myArray wasn't working correctly

https://codesandbox.io/s/type-string-issue-fixed-z9jth?file=/src/App.tsx

特别感谢Reactiflux的Brady帮助解决此问题。

我遇到了同样的问题,进行了以下更改,问题得到解决。

打开watchQueryOptions.d.ts文件

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

将查询类型更改为any而不是DocumentNode更改相同

之前:

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

后:

export interface QueryBaseOptions<TVariables = OperationVariables> {
    query: **any**;
本文地址:http://javascript.askforanswer.com/dazigaoleixingzifuchuanbukefenpeigeileixing.html
文章标签: ,   ,  
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!