typescript - 有时可能未定义的 Typescript 泛型参数的模式?
问题描述
我想要一个类层次结构,其中基类的某些实现允许未定义成员,而在其他情况下永远不会如此。我一整天都在尝试弄清楚如何问这个问题,因为我尝试了几种方法,并且根据我的工作遇到了不同的语言限制。我将尝试通过我尝试过的方法示例来总结问题:
function f(foo: Foo): number { return foo.bar; }
class Foo { bar: number; }
abstract class Base<T extends Foo | undefined> {
data: T;
public f(): number {
if (!this.data) { return -1; }
return f(this.data); // bad: this.data is still `Foo | undefined` not just `Foo`
}
}
class Always extends Base<Foo> {
constructor() { super(); this.data = new Foo(); }
}
class Sometimes extends Base<Foo | undefined> {}
let a = new Always();
let s = new Sometimes();
a.data.bar = 1; // good: no error because `a.data` must not be undefined
s.data.bar = 1; // good: compiler flags this because s.data can be undefined
上面我标记为“坏”的那一行是问题所在——因为您仍然无法缩小联合泛型的范围,因此无法使用简单的守卫来断言data
不是未定义的。我当然可以写f(this.data as Foo)
,但如果可能的话,我想避免在任何我引用它的地方都这样做。
我通过添加第二个泛型参数来简单地使用条件类型,extends boolean
但我也无法使其工作。基本上,我自己制定的所有解决方案都打破了示例中带有注释的 3 行之一 -- f(this.data)
,a.data.bar
始终有效,或者s.data.bar
如果您尚未检查s.data
已定义,则始终无效。
解决方案
如果您愿意使用第二个类型参数来表示未定义的可能性,则此方法有效:
function f(foo: Foo): number { return foo.bar; }
class Foo { bar: number; }
abstract class Base<T extends Foo, TUndefiend extends undefined> {
data!: T | TUndefiend;
public f(): number {
if (!this.data) { return -1; }
return f(this.data); // ok now
}
}
class Always extends Base<Foo, never> {
constructor() { super(); this.data = new Foo(); }
}
class Sometimes extends Base<Foo, undefined> {}
let a = new Always();
let s = new Sometimes();
a.data.bar = 1; // good: no error because `a.data` must not be undefined
s.data.bar = 1; // good: compiler flags this because s.data can be undefined
类型保护不会缩小到类型参数,但如果联合中存在两个不同的类型参数,它似乎工作得很好。
如果我们按原样传入并且派生类中的一切都按预期工作,那么额外的类型参数 ( TUndefined
) 将会消失。如果我们传入,那么我们必须再次检查未定义,如预期的那样never
T | never
T
Always
undefined
Sometimes
推荐阅读
- python - utils 不包含 progress_bar_downloader
- laravel - 审核模型时有没有办法指定特定用户?
- sparql - 如何在 DBpedia SPARQL 端点上检索特定节点的 pagerank 分数?
- java - 共享首选项值未立即更新
- java - 连接不可用,请求在 30002ms 后超时
- javascript - Laravel 8:为什么登录刀片不显示 Javascript 警报
- prolog - Prolog寻路在找到答案后陷入循环
- javascript - Javascript:Stripe 和 Apple Pay 网络设置
- python - 如何解释整数的布尔运算?
- c++ - 定义 std::pair C++17 时出错:构造函数不匹配