typescript - 函数参数的通用类型
问题描述
我试图理解一些对我来说看起来很明显的东西,但是 Typescript 似乎不允许使用所有严格的标志(当然有很好的理由)。让我告诉你:
我们都知道:
export interface Basic {
value: "foo" | "bar" | "baz";
}
export interface Constraint extends Basic {
value: "foo";
}
作品。但更令人惊讶的是(至少对我而言):
export interface WithFunctionsBasic {
value: (t: "foo" | "bar" | "baz") => void;
}
export interface WithFunctionsConstraint extends WithFunctionsBasic { // WithFunctionsConstraint extends incorrectly WithFunctionsBasic
value: (t: "foo") => void;
}
没有。
我们可以让它通用以允许我们这样的行为:
export interface WithFunctionsParametric<T extends Basic> {
value: (t: T["value"]) => void;
}
const variableConstraint: WithFunctionsParametric<Constraint> = { value: (t: "foo") => {} };
const variableBasic: WithFunctionsParametric<Basic> = { value: (t: "foo" | "bar" | "baz") => {} };
两者都有效。但这有点棘手,因为尽管 Constraint 扩展了 Basic:
const variableConstraint: WithFunctionsParametric<Constraint> = { value: (t: "foo") => {} };
const variableBasic: WithFunctionsParametric<Basic> = variableConstraint; // Not Working
据我了解,如果 Constraint 扩展 Basic(就是这种情况),后者应该可以工作。有人可以解释一下为什么吗?
解决方案
您的问题从根本上源于输入和输出在继承方面的行为方式之间的重要区别。
让我们看第一个例子:
export interface Basic {
value: "foo" | "bar" | "baz";
}
export interface Constraint extends Basic {
value: "foo";
}
在这里,Constraint
扩展Basic
。两者都有属性value
,但他们不同意它的类型。
Basic
说它必须是"foo"
,"bar"
或"baz"
. 很公平。Constraint
说它只能是"foo"
。这是兼容的,因为它是Basic
' 的一组有效值的子集。
换句话说,一个 的实例Constraint
不会破坏Basic
做出的承诺。value
仍然始终是"foo"
或"bar"
之一"baz"
。Constraint
只会输出一个的事实是无关紧要的;它仍然承诺返回值来自这三个值的集合。
现在,让我们看第二个例子:
export interface WithFunctionsBasic {
value: (t: "foo" | "bar" | "baz") => void;
}
export interface WithFunctionsConstraint extends WithFunctionsBasic { // WithFunctionsConstraint extends incorrectly WithFunctionsBasic
value: (t: "foo") => void;
}
现在,这是什么意思?好吧,WithFunctionsBasic
做出一个承诺:“我有一个名为的函数value
,它接受 a "foo"
、 a"bar"
或 a "baz"
”。
现在,WithFunctionsConstraint
extends WithFunctionsBasic
,这意味着它必须保持与做出的相同的承诺WithFunctionsBasic
。嗯,是吗?
不,不是的。它的value
功能只接受一个"foo"
. 换句话说,我们正在尝试创建一个WithFunctionsBasic
子类型来打破 a 的含义WithFunctionsBasic
,因为它的value
函数不能接受"bar"
or "baz"
。
当涉及到输出时,子类型必须具有相同或更强的限制。进一步限制输出的类型不会破坏超类型的承诺。在形式上,返回类型是协变的;他们被允许通过继承变得更加具体。
另一方面,当涉及到输入时,子类型必须具有相同或较弱的限制。也就是说,它必须至少接受相同的输入(以遵守承诺),但也可能允许超类型不允许的其他类型。在形式上,函数参数是逆变的;他们被允许通过继承变得不那么具体。
仅WithFunctionsConstraint
接受"foo"
是无效的,因为这意味着 aWithFunctionsConstraint
不是有效的WithFunctionsBasic
。但是,让它接受"foo"
、"bar"
、"baz"
和是完全有效的"lol"
。"wut"
您在问题中面临的其他问题似乎都是同一基本问题的不同变体。
推荐阅读
- apache-nifi - 如何将流文件从 NiFi 放入 Ignite 缓存
- c++ - 加权图的邻接表表示
- reactjs - 将对象带到另一个文件时对象嵌套
- html - 单击照片以显示信息
- javascript - 将数组拆分为给定范围之间的随机长度块
- php - 无法使用 codeigniter 将图像路径存储到数据库中 - 学生注册
- c# - 通过调用另一个表单中存在的变量来切换表单上的 LED
- ios - 如何仅在首次启动 iOS 应用程序(Swift)时呈现不同的视图控制器 - 以编程方式
- java - 利用 AlarmManager 触发 Notification
- java - 在每月 1 日和 16 日增加半月付款频率的给定日期