简体   繁体   中英

How does Class Casting work in Typescript

I have a question regarding 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

Can anybody explain this behaviour? And how is it possible also to inherit methods?

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 . 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. 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.

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 :

const x: Test = {id: 1};

This is just a developer convenience, because variables aren't typed in Javascript. This is where your linter comes into place and tells you there's an error.

Typescript is just a syntax help. It does not bring new functionality to the code. Your class syntax for example gets converted to normal 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. But a cast newer happens and none of the class properties have been inherited. It is only IDE support. If you want testData to be an instance of your class you have to do:

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

Then you can use 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).

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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