这是我在fruit.ts中所拥有的东西
export type Fruit = "Orange" | "Apple" | "Banana"
现在我在另一个打字稿文件中导入fruit.ts.这就是我所拥有的
myString:string = "Banana";
myFruit:Fruit = myString;
当我这样做时
myFruit = myString;
我收到错误:
键入' string'不能分配类型'" Orange" | "苹果" | "香蕉"'
如何将字符串分配给自定义类型Fruit的变量?
答案 0 :(得分:101)
您需要cast it:
export type Fruit = "Orange" | "Apple" | "Banana";
let myString: string = "Banana";
let myFruit: Fruit = myString as Fruit;
另请注意,使用string literals时,您只需使用一个|
答案 1 :(得分:13)
执行此操作时:
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
。
答案 2 :(得分:9)
我觉得这有点旧,但这里可能有更好的解决方案。
如果您需要字符串,但希望字符串仅匹配某些值,则可以使用enums。
例如:
enum Fruit {
Orange = "Orange",
Apple = "Apple",
Banana = "Banana"
}
let myFruit: Fruit = Fruit.Banana;
现在你知道,无论如何,myFruit永远都是字符串" Banana" (或者您选择的其他任何可枚举的值)。这对许多事情很有用,无论是将类似的值分组,还是将用户友好的值映射到机器友好的值,同时强制执行和限制编译器允许的值。
答案 3 :(得分:6)
在几种情况下,您会遇到此特定错误。对于OP,存在一个明确定义为字符串的值。因此,我必须假设这可能来自下拉列表,Web服务或原始JSON字符串。
在那种情况下,简单的强制转换<Fruit> fruitString
或fruitString as Fruit
是唯一的解决方案(请参阅其他答案)。您永远无法在编译时对此进行改进。
但是,在代码中使用从未打算为字符串类型的常量时,很容易遇到相同的错误。我的回答集中在第二种情况:
首先:为什么“魔术”字符串常量通常比枚举更好?
幸运的是,您定义了:
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!
为什么?这是打字稿,因此<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 = {字段:FieldName,错误:FieldError};
让我们说一个错误(字符串不可分配错误):
fieldErrors: [ { field: 'number', error: 'invalid' } ]
我们可以像这样FieldErrorType
“断言”整个对象:
fieldErrors: [ <FieldErrorType> { field: 'number', error: 'invalid' } ]
那我们就不必做<'invalid'> 'invalid'
。
但是错别字呢? <FieldErrorType>
不会只是断言在该类型右边的内容。并非在这种情况下-幸运的是,编译器将这样做会抱怨,因为它足够聪明,知道不可能:
fieldErrors: [ <FieldErrorType> { field: 'number', error: 'dog' } ]
答案 4 :(得分:6)
打字稿3.4
引入了新的'const'断言
您现在可以防止使用所谓的'orange'
断言将文字类型(例如'red'
或string
)“扩展”为键入const
。
您将能够做到:
let fruit = <const> 'orange';
然后它不会再变成string
了-这是问题中错误的根源。
答案 5 :(得分: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中导出。如果您需要单独使用size参数,则这很好。例如,您有一个函数可以接受或返回大小为type的参数,而您想键入它。
// 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)
));
答案 6 :(得分:1)
将道具传递到React组件时,我遇到了类似的问题。
原因:My type inference on myArray wasn't working correctly
https://codesandbox.io/s/type-string-issue-fixed-z9jth?file=/src/App.tsx
特别感谢Reactiflux的布雷迪为这个问题提供的帮助。
答案 7 :(得分:1)
在传播此错误的数组中仍然可能会引起一些误导:
export type Fruit = "Orange" | "Apple" | "Banana"
export type FruitArray = Fruit[];
const someFruits= ["Banana"];
const workingFruits: FruitArray = ["Orange", "Apple"]; // Works
// Even orange and apple show: Type 'string' is not assignable to type Fruit
const brokenAllFruits: FruitArray = [...someFruits, "Orange", "Apple"];
// As const is needed in the spread array
const someConstFruits= ["Banana" as const];
const workingAllFruits: FruitArray = [...someConstFruits, "Orange", "Apple"]; // Works
答案 8 :(得分:0)
例如,如果在模拟数据时要转换为dropdownvalue[]
,则将其组成具有值和显示属性的对象数组。
示例:
[{'value': 'test1', 'display1': 'test display'},{'value': 'test2', 'display': 'test display2'},]
答案 9 :(得分:0)
我遇到了同样的问题,我进行了以下更改,问题得到解决。
打开 watchQueryOptions.d.ts 文件
<nbdeploy clientUrlPart="${client.urlPart}" debugmode="false" forceRedeploy="${forceRedeploy}"/>
更改查询类型为 any 而不是 DocumentNode ,对于突变相同
之前:
\apollo-client\core\watchQueryOptions.d.ts
之后:
export interface QueryBaseOptions<TVariables = OperationVariables> {
query: **DocumentNode**;
答案 10 :(得分:0)
我收到了相同的错误消息,但情况略有不同。我来到这里寻找答案,但没有一个答案对我有用,所以我将与其他人分享我的解决方案。我没有自定义类型,它只是一个字符串数组。我有一个带有字符串属性 abcOrD 的对象 myObject,它必须是字符串数组中的值之一,例如 "a" "b" "c" 或 "d ”。尝试分配 myObject.abcOrD = myStringVar
时,它会给我一条错误消息 Type 'string' is not assignable to type "a" | "b" | "c" | "d"
。在玩弄并尝试了一些对我有用的事情之后,使用as any:
myObject.abcOrD = myStringVar as any;