有几种情况会出现此特定错误。对于 OP,有一个值明确定义为字符串。所以我不得不假设这可能来自下拉列表、Web 服务或原始 JSON 字符串。
在这种情况下,简单的演员<Fruit> fruitString 或fruitString as Fruit 是唯一的解决方案(请参阅其他答案)。您将永远无法在编译时对此进行改进。 [编辑:查看我关于<const>的其他答案]!
但是,在您的代码中使用从未打算成为字符串类型的常量时,很容易遇到同样的错误。我的回答集中在第二种情况:
首先:为什么'magic'字符串常量通常比枚举更好?
- 我喜欢字符串常量与枚举相比的外观 - 它紧凑且“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!
为什么?这是打字稿,所以<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!
解决问题的另一种方法是强制转换父对象:
我的定义如下:
export type FieldName = 'number' | '过期日期' | 'cvv';
导出类型 FieldError = 'none' | '失踪' | '无效的';
导出类型 FieldErrorType = { field: FieldName, error: FieldError };
假设我们得到一个错误(字符串不可分配错误):
fieldErrors: [ { field: 'number', error: 'invalid' } ]
我们可以像这样将整个对象“断言”为FieldErrorType:
fieldErrors: [ <FieldErrorType> { field: 'number', error: 'invalid' } ]
那我们就不用<'invalid'> 'invalid'了。
但是错别字呢? <FieldErrorType> 不只是 assert 任何属于那种类型的权利。在这种情况下不是 - 幸运的是,如果你这样做,编译器 会 抱怨,因为它足够聪明,知道这是不可能的:
fieldErrors: [ <FieldErrorType> { field: 'number', error: 'dog' } ]