Ren*_*aud 6 functional-programming typescript typeguards
我正在尝试使用类型保护来缩小复杂类型的范围。我希望类型保护的错误分支能够理解缩小类型的补充。
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';
}
Run Code Online (Sandbox Code Playgroud)
这似乎不可能,至少不是我要处理的方式。Typescript 很高兴推断 anEither可以是模型,但它不接受 aModel可以是Either. 这是一个错误:
declare const model: Model;
isLeft(model) // ts(2345)
Run Code Online (Sandbox Code Playgroud)
这个问题是根本无法解决的吗?
如果没有,我如何让错误分支缩小到补码?
请参阅此Typescript Playground 中的完整示例
编辑
在这个简单的例子中,Model和看起来Either是等价的,但这可能无法概括。我可以通过组合两个类型保护来取得一些进展,试图通知Model实际上有效的类型系统Either(参见这个新的Playground)。然而,这给我留下了一个不需要的分支(见第 22 行),所以并不完全令人满意。
有没有办法让类型系统知道Either并且Model严格等效?
我并不特别需要使用类型保护或联合类型,这是我第一次尝试解决这个问题,但也产生了它自己的问题。联合类型只有在我们能够保证缩小类型的联合及其相对补集确实等同于缩小的类型时才是可行的。这依赖于类型系统对补码的理解,但情况可能并非如此(目前)。请参阅此打字稿补充搜索和实用程序类型手册
有人建议使用fp-ts和/或monocle-ts来解决这个问题,但其中一些函数式编程概念仍然在我的脑海中。如果有人知道如何在这里应用它们,那会很好。无论是喜欢它的声音可以帮助这里...
实际上,您可以使用类型联合而不使用类型保护来做到这一点:
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
}
}
Run Code Online (Sandbox Code Playgroud)
from 的继承Model实际上是可选的,因为实际上是类型联合在这里完成工作。但它有助于将任何子类限制为仅“右”或“左”。
希望这就是您想要完成的事情吗?
虽然类型保护不是必需的,但仍然可以使用。它无法找出互补RightModel类型 - 但调用者可以通过已经约束为和value的并集来找出互补类型。LeftModelRightModel
interface Model { side: 'left' | 'right'; }
interface LeftModel extends Model { side: 'left'; }
interface RightModel extends Model { side: 'right'; }
function isLeft(value: Model): value is LeftModel {
return value.side === 'left';
}
function whatever(model: LeftModel | RightModel) { // This union makes the else branch work
model.side // left or right
if (isLeft(model)) {
model.side; // left - model is also LeftModel at this point
} else {
model.side; // right - model is a RightModel
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
152 次 |
| 最近记录: |