我正在尝试使用类型防护来缩小复杂类型的范围。我希望类型保护的虚假分支能够理解complement到缩小类型。
interface Model { side: 'left' | 'right'; }
interface LeftModel { side: 'left'; }
interface RightModel { side: 'right'; }
type Either = LeftModel | RightModel;
function isLeft(value: Either): value is LeftModel { // else is RightModel
return value.side === 'left';
}
这似乎是不可能的,至少不是我要这么做的方式。 Typescript很高兴推断出Either
可以是模型,但是它不接受Model
可以是Either
。这是一个错误:
declare const model: Model;
isLeft(model) // ts(2345)
这个问题从根本上解决吗?
如果没有,我如何获得假分支以缩小到补码?
中的完整示例编辑
在这个幼稚的示例中,Model
和Either
似乎是等效的,但这可能不能一概而论。我可以通过组合两个类型防护程序来取得一些进展,以试图通知类型系统Model
实际上是有效的Either
(请参阅新的Playground)。但是,这给我留下了一个多余的分支(请参见第22行),因此并不完全令人满意。
是否可以让类型系统知道Either
和Model
是严格等价的?
我并不需要特别使用类型保护或联合类型,这是我第一次尝试解决问题,但是却产生了自己的问题。联合类型只有在我们可以保证缩小类型的联合及其相对互补量确实等于缩小类型的联合时才可行。这取决于类型系统对补码的理解,但事实并非如此。参见此typescript complement search和handbook on utility types
有人建议使用fp-ts和/或monocle-ts来解决这个问题,但是其中一些功能性编程概念仍然困扰着我。如果有人知道如何在这里应用它们,那会很好。 Either听起来可能对您有帮助...
答案 0 :(得分:2)
联合运算符|
不会对联合中指定的类型的属性的类型执行联合。
即
type Either = LeftModel | RightModel === { side: 'left ' } | { side: 'right' }
!== { side: 'left' | 'right' } === Model
Either
严格是LeftModel
和RightModel
的联合,而不是类型side
和side
的联合
错误的摘录,我认为这说明了一切
“模型”类型的参数不能分配给“任何”类型的参数。 类型“模型”不可分配给类型“ RightModel”。 属性“边”的类型不兼容。 输入'“ left” | “ right”不能分配给“ right”类型。 不能将类型““ left”'分配给类型“” right“'。
答案 1 :(得分:1)
实际上,您可以使用类型联合并没有类型保护器来做到这一点:
Exception: Java gateway process exited before sending its port number
从interface Model { side: 'left' | 'right'; }
interface LeftModel extends Model { side: 'left'; }
interface RightModel extends Model { side: 'right'; }
function whatever(model: LeftModel | RightModel) {
model.side // left or right
if (model.side === 'left') {
model.side; // left - model is also LeftModel at this point
} else {
model.side; // right - model is a RightModel
}
}
的继承实际上是可选的,因为它实际上是在这里进行工作的类型联合。但这有助于将所有子类仅限制为“右”或“左”。
希望这是您要完成的事情?
虽然不需要类型防护,但仍可以使用它。它无法找出互补的Model
类型-但调用者可以通过将RightModel
约束为value
和LeftModel
的并集来实现。
RightModel