首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >带有子/父参数的类型记录方法不可分配

带有子/父参数的类型记录方法不可分配
EN

Stack Overflow用户
提问于 2022-08-21 11:58:00
回答 2查看 95关注 0票数 2

为什么这在打字稿中行不通?

代码语言:javascript
运行
复制
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 };

至少对我来说这个错误是很奇怪的:

代码语言:javascript
运行
复制
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'

它似乎是在尝试将一个父对象分配给一个子,但是实际代码中的代码是向后的(试图将一个方法参数分配给父,这个方法参数就是)。这是有道理的,因为孩子是一群超级家长)

我是不是遗漏了什么?

我们可以在这里验证这一点:https://www.typescriptlang.org/play?#code/MYGwhgzhAEAKYCcCmA7ALtA3gKGn6AlgCYBc0EaCBKA5tALzQDkT2AvttqJDAMIAWBEEWhIAHmlREY8ZOhz5oKMAFskZClVoNmrDpy4B7FBWgAzMEIhkAFMGRhJpOIlRoAlAwB80AG6HiHTsHJzIBISJPeh9MaGQ0AFcEFGg2AG4jEwwLKwAVQ0NbWPskRyQRNjJikPKyWTdUqJ9-QMYbatKnVKroErLncOFG7yw4pETk1LSgA

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 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)。这是一个自然的结果,类型理论,但是您可以通过想象尝试将更窄/更宽的类型传递给比他们预期的函数,并看到所发生的事情,从而使自己相信这是必要的。例如,假设这是成功的:

代码语言:javascript
运行
复制
const fails: (created: Parent) => void =
    (created: Child) => { created.name.toUpperCase() };

函数(created: Child) => { created.name.toUpperCase() }本身很好;它接受Child并访问它的name属性(即string ),因此它有一个toUpperCase()方法。但是您已经将它分配给了一个类型为(created: Parent) => void的变量。这意味着您可以这样调用fails()

代码语言:javascript
运行
复制
fails(new Parent()); // okay at compile time, but
//  RUNTIME ERROR! created.name is undefined

如果fails()接受任何Parent,那么您可以传递给它一个不是Childnew Parent()。但是现在您有一个运行时错误,因为在运行时,您试图访问不存在的toUpperCase()实例的name属性的Parent方法。噢,我们在某个地方犯了个错误。

错误就在于你不能扩大函数所期望的类型。如果启用了这种不正确的参数,TypeScript将有助于报告错误,这是推荐的。

不能扩大参数类型,但可以缩小参数类型。如果您有一个GrandChild子类,您就可以在没有问题的情况下做到这一点:

代码语言:javascript
运行
复制
class GrandChild extends Child {
    age: number = 1;
}
const okay: (created: GrandChild) => void =
    (created: Child) => { created.name.toUpperCase() };

okay(new GrandChild()); // okay

这很好,因为okay()只能接受GrandChild实例,每个实例都是Child实例,这正是函数实现所期望的。这个实现不知道它被赋予了GrandChildren,所以它不能访问age属性,但是这样做是安全的。

经验法则是,当类型出现在输入位置时,就像函数参数一样,类型方差的方向与输出位置的方向相反。

操场链接到代码

票数 2
EN

Stack Overflow用户

发布于 2022-08-21 12:41:13

如果查看fails的类型定义,则必须能够将父文件传递给in。这意味着您得到的函数的实现可能会出现运行时错误,例如

代码语言:javascript
运行
复制
const fails: (created: Parent) => void = (created: Child) => {
   console.log(created.name)
   return
}

fails({ id: 'foo' })

这将在运行时失败,因为传入的参数上不存在字段名。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73434198

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档