【发布时间】:2022-01-05 16:42:14
【问题描述】:
我见过的大多数 Maybe/Option 类型的 Typescript 实现要么使用带有标签的接口来区分 Some/None 变体。我见过一些没有并且实际上有 Some 和 None 的单独类,它们都实现了一个通用的 Option 接口。作为一个实验,我想尝试一个使用继承的实现。所以这是我想出的简化版本:
abstract class Maybe<T> {
constructor(private value: T) {}
isSome(): this is Some<T> {
return this instanceof Some;
}
isNone(): this is None {
return !this.isSome();
}
and<U>(other: Maybe<U>): Maybe<U> {
return this.isNone() ? new None() : other;
}
unwrap(): T {
if (this.isNone()) throw new Error('called unwrap() on None');
return this.value;
}
unwrapOr(defaultValue: T): T {
return this.isNone() ? defaultValue : this.value;
}
}
class Some<T> extends Maybe<T> {
constructor(value: T) { super(value); }
}
class None extends Maybe<any> {
constructor() { super(null); }
}
但是我在None 类上将类型传递给extends Maybe<...> 时遇到了一些问题。我曾尝试使用never、null 和any,它们都会导致(不同的)编译器错误,迫使我在Maybe's 方法中进行一些奇怪的转换。
你可以找到上面代码here的游乐场。
这是我的想法。 Maybe 上的泛型 Type T 表示包含值的类型,可以是任何类型。但是当Maybe 是None 时,它确实应该是never,因为从概念上讲,它没有包含值。与此保持一致,我的第一个想法是让None 扩展Maybe<never>,但随后对super(null) 的调用会触发编译器错误,因为null 不能分配给类型never。
我想出的最有用的版本是 None 扩展 Maybe<any> 的版本,但这需要在 Maybes 方法中进行一堆 (<Some<T>this).value 的转换(上面的代码中没有显示),我不喜欢那样。理想情况下,我想找到一个不需要使用any 并在各处进行强制转换的实现。任何有助于实现这一目标的帮助将不胜感激。
【问题讨论】:
-
Ehh,确实没有可以分配给
never的值,因此您可以编写super(null!)并在那里进行一种类型的断言并继续前进。或者你可以重构,这样基类就不会假装做它不能做的事情(比如保持never值),比如this。不确定您想在此处做什么或将其视为答案。 -
@jcalz 感谢您的快速反馈。我从未想过在
super(null)调用中直接进行!类型断言。但实际上,像你建议的那样重构类可能是要走的路。所以如果你想写一个答案,我会去的。
标签: typescript class inheritance optional maybe