1. 联合类型方法
我认为你想做的是确定一些属性关系。直接获取不同类型并强制转换为另一个类型是错误的。我认为你的 Item
类型在某些情况下可以具有一些附加属性,我们应该在类型定义中对其进行建模!
让我们从正确的类型开始:
type ItemNoFoo = { name: string };
type ItemWithFoo = ItemNoFoo & {foo: string}
type Item = ItemNoFoo | ItemWithFoo;
我将创建一个 ItemNoFoo
和 ItemWithFoo
的联合体作为项。感谢这样我们可以定义对象的两种不同状态。
现在我将创建一个守卫函数,用于检查我们是处于 ItemNoFoo
还是 ItemWithFoo
状态。
const hasFoo = (item: Item): item is ItemWithFoo => item.name === 'test';
好的,现在我们可以在一个类型的作用域内(因为我们的类型只是两个其他类型的联合)询问 Item
是否拥有属性 foo。
最终代码:
type ItemNoFoo = ;
type ItemWithFoo = ItemNoFoo &
type Item = ItemNoFoo | ItemWithFoo;
const hasFoo = (item: Item): item is ItemWithFoo => item.name === 'test';
function addProp(obj: Item)
}
关于这种方法的更多信息,您可以在此处找到 - Sum types
2. 函数作为数据转换器
如果我们的函数需要创建一个新结构,就像是一个数据创建器或者数据转换器,那么我们应该将其视为一个in -> out
管道。在类型中,in类型是ItemNoFoo
,out类型是ItemWithFoo
| ItemWithFoo
(参见第1点中的类型定义)。
function transform(obj: ItemNoFoo): Item {
if (obj.name === 'test') {
return {
...obj,
foo: 'hello'
}
} else {
return obj;
}
}
正如您所看到的,联合类型Item
仍然很方便,因为此函数返回或未更改的ItemNoFoo
类型实例或ItemWithFoo
实例。
让我们来看一下它的使用:
function f(item: ItemNoFoo) {
const finalItem = transform(item); // type of finalItem is ItemWithFoo | ItemNoFoo
}
如果你想确定你正在处理的是哪个值,那么有用的方法可以是 hasFoo
保护函数(在解决方案1中定义),该函数将确定这两种类型中的哪一种。
type
吗?在我的情况下,obj
的type
将永远是Item
,我无法将其type
更改为另一个,即使是兼容的type
?请参见此playground。 - JessWithFoo
更改为type WithFoo = { foo?:string; name:string; }
,则转换将失败。请参见此播放列表。 - Jessobj
的类型成为可分配给Item | WithFoo
中每个组成类型的联合。在您的最后一个示例中,WithFoo
可以分配给Item
和WithFoo
,因此结果类型再次为Item | WithFoo
。但是 TypeScript 抱怨,因为联合的所有组成部分中都没有foo
属性(它可能是Item
,那么您就不能使用foo
)。 - ford04