当前位置: 首页 > 知识库问答 >
问题:

Typescript继承:扩展基类对象属性

顾乐家
2023-03-14

我在挣扎。

当扩展一个类时,我可以很容易地向它添加一些新属性。

但是,当我扩展基类时,如果我想向基类的对象(简单对象的属性)添加新属性,该怎么办?

下面是一个带有一些代码的示例

基类

type HumanOptions = {
  alive: boolean
  age: number
}

class Human {
  id: string
  options: HumanOptions

  constructor() {
    this.id = '_' + Math.random()

    this.options = {
      alive: true,
      age: 25,
    }

  }
}

派生类

type WizardOptions = {
  hat: string
} & HumanOptions

class Wizard extends Human{
 
  manaLevel: number
  options: WizardOptions // ! Property 'options' has no initializer and is not definitely assigned in the constructor.

  constructor() {
    super()
    this.manaLevel = 100
    this.options.hat = "pointy" // ! Property 'options' is used before being assigned.
  }
}

现在,正如您可以从行内注释中看到的,这将激怒TypeScript。但这在JavaScript中工作。那么,实现这一目标的正确方法是什么呢?如果没有,问题是在我的代码模式本身吗?什么模式适合这个问题?

也许您想知道为什么我要在options对象中使用这些属性。它可能非常有用!例如:只有选项中的属性才能通过某些UI进行编辑。因此,其他一些代码可以在类中动态查找选项,并在UI上公开/更新它们,同时像idmanaLevel这样的属性将被忽略。

笔记

我知道我可以为向导这样做:

class Wizard extends Human{
 
  manaLevel: number

  options: {
    hat: string
    alive: boolean
    age: number
  }

  constructor() {
    super()
    this.manaLevel = 100
    this.options = {
      alive: true,
      age: 25,
      hat: "pointy"
    }
  }
}

但是代码不是很干燥,我必须手动管理选项继承(这在复杂的应用程序中是不理想的)。

共有3个答案

禄源
2023-03-14

这是部分答案,我会在你提供更多信息时更新。例如,上面你问题下的问题的答案。

第二个错误是您在Wizard中声明的选项字段的结果。

这在Javascript中起作用,因为您依赖于原型继承,并且没有在向导类中声明新的选项字段(如果有的话,该类也会隐藏Human.options)。

阙博容
2023-03-14

你可以用以下方法来做:操场

type HumanOptions = {
  alive: boolean
  age: number
}

class Human<Options extends HumanOptions> {
  id: string
  options: Options

  constructor() {
    this.id = '_' + Math.random()

    this.options = {
      alive: true,
      age: 25,
    } as Options
  }
}

type WizardOptions = {
  hat: string
} & HumanOptions

class Wizard extends Human<WizardOptions> {
  manaLevel: number

  constructor() {
    super()
    this.manaLevel = 100
    this.options.hat = "pointy"
  }
}

请注意,您完全负责设置选项的所有必需道具。

轩辕鸿祯
2023-03-14

如果您只是要重用超类中的属性,但将其视为更窄的类型,您可能应该在子类中使用声明属性修饰符,而不是重新声明字段:

class Wizard extends Human {
  manaLevel: number
  declare options: WizardOptions; // <-- declare
  constructor() {
    super()
    this.manaLevel = 100
    this.options.hat = "pointy" // <-- no problem now
  }
}

在这里使用declare可以抑制该行的任何JavaScript输出。它所做的只是告诉TypeScript编译器,在向导中,选项属性将被视为向导选项,而不仅仅是人类选项

公共类字段目前处于TC39过程的第3阶段,因此很可能是当前形式的JavaScript的一部分,或者与之相近。当这种情况发生时(或者现在如果你有一个足够新的JS引擎的话),你编写的代码最终会生成如下的JavaScript

class Wizard extends Human {
    manaLevel;
    options; // <-- this will be here in JavaScript
    constructor() {
        super();
        this.manaLevel = 100;
        this.options.hat = "pointy";
    }
}

这只是没有类型注释的TypeScript。但是JavaScript中的options声明将子类中的options初始化为undefined。因此,在分配之前使用此选项将是正确的:

console.log(new Wizard()); // runtime error!
// this.options is undefined

所以你从TypeScript得到的错误是一个很好的错误。

最初,TypeScript实现了类字段,因此如果不显式初始化字段,则仅声明字段不会产生效果。TypeScript团队认为类字段最终将在JavaScript中实现。但他们错了。如果您的编译器选项没有启用--使用定义或类字段(请注意,如果您将--目标设置得足够新,它将自动包括在内;请参见microsoft/TypeScript#45653),那么它将输出JS代码,而您的示例不会出现运行时错误。

因此,您可以争辩说,如果您没有使用--useDefeForClassFields,编译器不应该给您一个错误。在--use定义ForClassFields存在之前,这样的论点实际上是在微软/TypeScript#20911和微软/TypeScript#21175上提出的。

但是我认为TS团队不再太接受这个了。随着时间的推移,JavaScript中声明的类字段被初始化为未定义的将是常态,而不是例外,支持旧的不一致版本的类字段不是任何人的优先事项。请参阅microsoft/TypeScript#35831,其中的建议基本上是使用声明。这也是我在这里的建议。

操场连结至守则

 类似资料:
  • 本文向大家介绍TypeScript 基本继承,包括了TypeScript 基本继承的使用技巧和注意事项,需要的朋友参考一下 示例 本示例说明如何Car使用extends关键字创建该类的非常简单的子类。的SelfDrivingCar类重写move()方法和用途使用基类FPGA实现super。

  • 我在下棋。我想做一个抽象的piece类,然后可以通过pawn/knight/rook/等进行扩展。假设我的piece类是这样的: 我希望Pawn具有相同的sayName功能,但我希望它具有不同的movePiece功能,因为Pawn有自己独特的移动方式。我怎么做典当,使它扩展件,并覆盖件的移动件功能?

  • 问题内容: 是否有理由要声明类声明object? 我刚刚找到了执行此操作的代码,但找不到很好的理由。 问题答案: 是否有理由要声明类声明object? 在Python 3中,除了Python 2和3之间的兼容性之外,没有任何理由。在Python 2中,原因很多。 Python 2.x故事: 在Python 2.x(从2.2开始)中,有两种类型的类,取决于是否存在object作为基类的类: “经典”

  • 问题内容: 我对使用python list对象感兴趣,但功能略有改变。特别是,我希望列表是1索引而不是0索引。例如: 输出应为:1 但是,当我更改和方法来执行此操作时,出现了错误。我对这些方法进行了很多修改,但这基本上就是我在那里做的: 我想问题是它本身正在调用与定义的方法相同的方法。如果是这样,如何使它使用方法而不是方法?我尝试使用代替,但导致投诉 有任何想法吗?另外,如果您可以为此指出一个好的

  • 我目前正在尝试使用JaxB,但对于一个相对简单的示例,我并不是很成功。我的示例如下: 我所有的尝试(甚至编组)都失败了。我浏览了BlaiseDoughan的博客,包括http://blog.bdoughan.com/2010/11/jaxb-and-inheritance-using-xsitype.html但他们似乎对我的例子都没有帮助。我很可能误用了他的例子。在我看来,我的示例应该是JaxB中

  • FAQs in section [22]: [22.1] 将接口和实现分离的作用是什么? [22.2] 在C++中如何分离接口和实现(就象 Modula-2)? [22.3] 什么是 ABC? [22.4] 什么是“纯虚”成员函数? [22.5] 如何为包含指向(抽象)基类的指针的类定义拷贝构造函数或赋值操作符? 22.1 将接口和实现分离的作用是什么? 接口是公司最有价值的资源。设计接口比用一堆