【问题标题】:What is the difference between type and class in Typescript?Typescript 中的类型和类有什么区别?
【发布时间】:2018-12-10 10:18:08
【问题描述】:

typeclass 有什么区别?

type Point {
  x: number, y: number
}

let p = new Point();

以上结果:

'Point' 仅指一种类型,但在这里用作值。

为什么会这样?我肯定不是不使用Point 作为值,而是使用它来实例化一个类型。

在哪些情况下我需要使用type,因为class 不适合?

【问题讨论】:

  • TypeScript/JavaScript 类是一个函数。 TypeScript 类型只是帮助 TS 编译器检查代码的定义。它不会在生成的 JS 代码中翻译成任何东西。
  • @OldGeezer:再次阅读评论。这只是对编译器的类型提示。在javascript中转换为absolutely nothing。你不能实例化任何东西。
  • let p: Point = { x: 10, y: 15 }; 在 Sefe 和 Titian 的回答中是我要问的。

标签: typescript


【解决方案1】:

Typescript 有两个不同的领域,它们在某些方面相互接触:值空间和类型空间。类型空间是定义类型的地方,类型被完全擦除并且在运行时不存在。值空间包含值并且显然会在运行时存在。

什么是价值?值文字、变量、常量和参数显然是值。函数和类声明也是值,因为它们确实有一个运行时对象支持它们,即函数对象和类构造函数(也是一个函数)。 枚举也是值,因为它们在运行时由对象备份。

什么是类型?任何带有type 关键字的定义都是类型以及接口、类声明枚举

你会注意到我在两个空格中都提到了类声明。类存在于类型空间和值空间中。这就是为什么我们可以在类型注释(let foo: ClassName)和表达式(例如new ClassName())中使用它们。

枚举也跨越了两个世界,它们也代表了我们可以在注解中使用的类型,以及将保存枚举的运行时对象。

类型空间和值空间中的名称不会冲突,这就是为什么我们可以同时定义同名的类型和变量:

type Foo = { type: true }
var Foo = { value : true } // No error, no relation to Foo just have the same name in value space 

类声明和枚举,因为它们跨越两个空格将“用完”两个空格中的名称,因此我们不能定义与类声明或枚举同名的变量或类型(尽管我们可以这样做合并,但这是一个不同的概念)

在您的特定情况下,Point 只是一个类型,我们可以在类型注释中使用它,而不是我们可以在需要运行时存在的表达式中使用它。在这种情况下,该类型很有用,因为它允许编译器在结构上检查对象字面量是否可分配给 Point 类型:

let p: Point = { x: 10, y: 15 }; // OK
let p: Point = { x: 10, y: 15, z: 10 }; // Error

如果你想创建一个类,你需要使用 class 关键字来实现,因为这将创建一个不仅仅是类型的运行时值:

class Point{
    constructor(public x: number, public y: number){}
}
let p = new Point(10,10)

【讨论】:

  • 关于类型空间与值空间的任何文档?
【解决方案2】:

您使用 type(或在其他情况下为 interface)作为类型注释来指示 JavaScript 对象的结构:

type Point = {
  x: number, y: number
}

function doSomething(p: Point) {
}

let p: Point = { x: 10, y: 15 };
doSomething(p);

这些类型注释受结构类型的影响,这意味着在这种特定情况下,您可以删除类型注释:

let p = { x: number, y: number };
doSomething(p);

类是完全不同的东西,它为您提供了一个更优雅的 JS 原型继承替代方案:

class Point {
    public x: number;
    public y: number;

    constructor(x: number, y: number) {
        this.x = x;
        this.y = y;
    }

    public move(deltaX: number, deltaY: number) {
        this.x = this.x + deltaX;
        this.y = this.y + deltaY;
    }
}

let p = new Point(10, 15);
p.move(1, 2);

当你查看生成的 JS 代码时,你会很快注意到不同之处:

The type declaration is dropped in the generated code.

The class definition is turned into a JS function with prototype inheritance

【讨论】:

    【解决方案3】:

    为了更好地理解,我为所有差异创建了一个表:

    | Description                                             | Type | Interface |
    |---------------------------------------------------------|------|-----------|
    | Describe functions                                      |   ✔  |     ✔     |
    | Describe constructors                                   |   ✔  |     ✔     |
    | Describe tuples                                         |   ✔  |     ✔     |
    | Interfaces can extend                                   |   ≈  |     ✔     |
    | Classes can extend                                      |   ✘  |     ✔     |
    | Classes can implement                                   |   ≈  |     ✔     |
    | Divide another one of its own kind                      |   ✔  |     ≈     |
    | Create a union with another one of its own kind         |   ✔  |     ✘     |
    | Be used to create mapped types                          |   ✔  |     ✘     |
    | Be mapped over with mapped types                        |   ✔  |     ✔     |
    | Expands in error messages and logs                      |   ✔  |     ✘     |
    | Be completed                                            |   ✘  |     ✔     |
    | Be recursive                                            |   ≈  |     ✔     |
    
    Hint: `≈` means partially
    

    可能是TypeScript的新版本,这个表格有一些变化,如果有请通过编辑当前帖子来修复这个表格。

    【讨论】:

      【解决方案4】:
      class myClass extends myParentClass implements myInterface{
      
      }
      
      let value = new myClass();
      
      // value is from type any and from type myClass and from type myParentClass and from type myInterface. Its class is myClass
      

      您只能将 new 与类名一起使用。但是 Point 不是类名,而是一个值。

      class Point{
          private x;
          private y;
          constructor(x,y) {
              this.x = v1;
              this.y = v2;
          }
      }
      

      现在 Point 是一个类,你可以这样做:

      let p = new Point(1,2);
      

      【讨论】:

      • But Point is not a classname, but a value,不,这就是重点。它仅在类型空间中定义;这里最重要的一点是类型不是值。
      猜你喜欢
      • 2019-09-02
      • 2010-10-02
      • 2020-05-23
      • 2023-02-18
      • 1970-01-01
      • 1970-01-01
      • 2010-12-11
      • 2014-02-16
      • 1970-01-01
      相关资源
      最近更新 更多