简体   繁体   English

Class Casting如何在Typescript中工作

[英]How does Class Casting work in Typescript

I have a question regarding Casting in Typescript . 我有一个关于Casting in Typescript的问题。

I had the Use Case that I casted a object to a specific type of a class which had a method. 我有一个用例,我将一个对象转换为一个具有方法的类的特定类型。 When I afterwards wanted to call this method, it was undefined, compare the snippet below: 当我之后想要调用此方法时,它是未定义的,比较下面的代码段:

export class Test {
  property1: any;
  property2: any;

  constructor(){}

  sayHello(): string {
    return 'hello';
  }
}


testData = {
    property1: '',
    property2: 2
  } as Test;

testData.sayHello(); <-- undefined

I also prepared a working or rather not working example in an angular application on stackblitz: https://stackblitz.com/edit/angular-y3s9r4 我还在stackblitz的角度应用程序中准备了一个工作或非工作的例子: https ://stackblitz.com/edit/angular-y3s9r4

Can anybody explain this behaviour? 任何人都可以解释这种行为吗? And how is it possible also to inherit methods? 如何inherit方法呢?

In typescript this is called a type assertion, not a cast. 在打字稿中,这称为类型断言,而不是强制转换。 The reason for the different terminology is exactly that this behaves differently from other languages, namely there is no runtime behavior. 不同术语的原因恰恰在于其行为与其他语言不同,即没有运行时行为。 Type assertion do not convert values and do not perform any runtime checks, they only tell the compiler that you, as the developer, know that a certain value will be of certain type. 类型断言不转换值并且不执行任何运行时检查,它们只告诉编译器您作为开发人员知道某个值将是某种类型。 How you have this knowledge is none of the compiler's business. 你如何掌握这些知识并不是编译器的业务。

So this code : 所以这段代码:

testData = {
    property1: '',
    property2: 2
  } as Test;

Just tells the compiler that the object literal is of the type Test . 只是告诉编译器对象文字是Test类型。 The object literal has the same fields as your class but it will have none of the methods (since nobody put them there). 对象文字与您的类具有相同的字段,但它没有任何方法(因为没有人将它们放在那里)。

To create an instance of the class you must use the new operator with the class constructor. 要创建类的实例,必须将new运算符与类构造函数一起使用。 If you want to pass in the data you can have a constructor that accepts the data and will assign it to the current instance: 如果要传入数据,可以使用接受数据的构造函数并将其分配给当前实例:

export class Test {
    property1: any;
    property2: any;

    constructor(data: Partial<Test>) {
        Object.assign(this, data);
    }

    sayHello(): string {
        return 'hello';
    }
}


let testData = new Test({
    property1: '',
    property2: 2
});

testData.sayHello();  //ok 

There's a difference between plain objects, and class instances. 普通对象和类实例之间存在差异。 Let me explain this in Javascript. 让我用Javascript解释一下。

When you write this : 当你写这个:

const x = { id: 0 };

it is translated to this : 它被翻译成这个:

const x = { id: 0 };

But when you write this 但是当你写这个

class Test { 
  id = 0;

  getId() { 
   return this.id; 
 } 
}
const x = new Test();

It translates to this : 它转化为:

function Test() {
  this.id = 0;

  this.getId = () => this.id;
}
const x = new Test();

As you can see, in the first case, there's no function. 如您所见,在第一种情况下,没有任何功能。 In the second case, there is. 在第二种情况下,有。

When you write this in Typescript : 当你在Typescript中写这个:

const x: Test = {id: 1};

This is just a developer convenience, because variables aren't typed in Javascript. 这只是开发人员的便利,因为变量不是在Javascript中输入的。 This is where your linter comes into place and tells you there's an error. 这是你的linter到位并告诉你有错误的地方。

Typescript is just a syntax help. Typescript只是一种语法帮助。 It does not bring new functionality to the code. 它没有为代码带来新功能。 Your class syntax for example gets converted to normal JavaScript. 例如,您的类语法将转换为普通JavaScript。 If you create an object like you did, it is just the object with nothing else. 如果你创建一个像你一样的对象,它只是没有别的对象。 By using as Test the IDE shows you the properties and pretends a cast. 通过使用as Test ,IDE将显示属性并假装强制转换。 But a cast newer happens and none of the class properties have been inherited. 但是会发生一个更新的版本,并且没有任何类属性被继承。 It is only IDE support. 它只是IDE支持。 If you want testData to be an instance of your class you have to do: 如果您希望testData成为您的类的实例,您必须:

let testData = new Test();
testData.property1 = 'test';

Then you can use testData.sayHello() 然后你可以使用testData.sayHello()

Type casting just makes the transpiler think that each instance is of a type. 类型转换只是让转换器认为每个实例都是一个类型。 At no point, does it create an actual instance of that class for you. 在任何时候,它都不会为您创建该类的实际实例。

Type casting is inherently dangerous, as you lose compile time checks and it may break at runtime if your actual data structures are not behaving according to your interface. 类型转换本质上是危险的,因为您丢失了编译时检查,如果您的实际数据结构不符合您的界面,它可能会在运行时中断。

There are valid use cases for type casting (eg you have an external well-defined JSON from a remote endpoint and you want define its structure, I often type cast the response to an interface). 类型转换有一些有效的用例(例如,你有一个来自远程端点的外部定义良好的JSON,你想要定义它的结构,我经常输入对接口的响应)。

Yet if you want to have actual methods on your instances, you have to create them. 但是,如果您希望在实例上使用实际方法,则必须创建它们。 You have to use the constructor and pass in the appropriate values. 您必须使用构造函数并传入适当的值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM