为什么这在打字稿中行不通?
class Parent {
id: string = ''
}
class Child extends Parent{
name: string = ''
}
const fails: (created: Parent) => void = (created: Child) => { return };
const failsToo: ({ created }: { created: Parent }) => void = ({ created }: { created: Child }) => { return };
至少对我来说这个错误是很奇怪的:
Type '(created: Child) => void' is not assignable to type '(created: Parent) => void'.
Types of parameters 'created' and 'created' are incompatible.
Property 'name' is missing in type 'Parent' but required in type 'Child'
它似乎是在尝试将一个父对象分配给一个子,但是实际代码中的代码是向后的(试图将一个方法参数分配给父,这个方法参数就是)。这是有道理的,因为孩子是一群超级家长)
我是不是遗漏了什么?
发布于 2022-08-21 12:52:09
函数类型在其参数类型中是https://stackoverflow.com/questions/66410115/difference-between-variance-covariance-contravariance-and-bivariance-in-typesc。类型反变.它们在相反的方向上彼此不同。如果是A extends B
,那么是((x: B)=>void) extends ((x: A)=>void)
,而不是((x: A)=>void) extends ((x: B)=>void)
。这是一个自然的结果,类型理论,但是您可以通过想象尝试将更窄/更宽的类型传递给比他们预期的函数,并看到所发生的事情,从而使自己相信这是必要的。例如,假设这是成功的:
const fails: (created: Parent) => void =
(created: Child) => { created.name.toUpperCase() };
函数(created: Child) => { created.name.toUpperCase() }
本身很好;它接受Child
并访问它的name
属性(即string
),因此它有一个toUpperCase()
方法。但是您已经将它分配给了一个类型为(created: Parent) => void
的变量。这意味着您可以这样调用fails()
:
fails(new Parent()); // okay at compile time, but
// RUNTIME ERROR! created.name is undefined
如果fails()
接受任何Parent
,那么您可以传递给它一个不是Child
的new Parent()
。但是现在您有一个运行时错误,因为在运行时,您试图访问不存在的toUpperCase()
实例的name
属性的Parent
方法。噢,我们在某个地方犯了个错误。
错误就在于你不能扩大函数所期望的类型。如果启用了这种不正确的参数,TypeScript将有助于报告错误,这是推荐的。
不能扩大参数类型,但可以缩小参数类型。如果您有一个GrandChild
子类,您就可以在没有问题的情况下做到这一点:
class GrandChild extends Child {
age: number = 1;
}
const okay: (created: GrandChild) => void =
(created: Child) => { created.name.toUpperCase() };
okay(new GrandChild()); // okay
这很好,因为okay()
只能接受GrandChild
实例,每个实例都是Child
实例,这正是函数实现所期望的。这个实现不知道它被赋予了GrandChild
ren,所以它不能访问age
属性,但是这样做是安全的。
经验法则是,当类型出现在输入位置时,就像函数参数一样,类型方差的方向与输出位置的方向相反。
发布于 2022-08-21 12:41:13
如果查看fails的类型定义,则必须能够将父文件传递给in。这意味着您得到的函数的实现可能会出现运行时错误,例如
const fails: (created: Parent) => void = (created: Child) => {
console.log(created.name)
return
}
fails({ id: 'foo' })
这将在运行时失败,因为传入的参数上不存在字段名。
https://stackoverflow.com/questions/73434198
复制相似问题