TypeScript could give you a false hope that I’ve got a strong-typed code and everything will work as expected with JavaScript. In reality, TypeScript doesn’t do anything after sources are compiled to JavaScript. It means, in runtime, you’ll face good-known JavaScript with it dynamic typing.
The lack of any runtime type checking is a big minus for TypeScript. You’ll lose all your type at the same moment when browser executes code.
I’d got a pretty simple code in my Vue component:
data() {
return {
clouds: Array<Cloud>(),
};
}
And I use Axios to work with AJAX. I know that it’s a good time to use Fetch API but it’s a different story. My code looks like:
axios.get('/api/clouds/')
.then((response) => {
this.clouds = response.data;
});
And here is Cloud class definition:
export class Cloud {
public created_at: Date;
public description: string;
public name: string;
public nodes: object;
public updated_at?: Date;
public id: string;
}
}
I skipped some code to make it cleaner and fit it in the blog.
If you are experienced with TypeScript, probably you understand already what
goes wrong. When I do this.clouds = response.data;
, a browser will execute
compiled to JavaScript code which doesn’t know anything about Cloud
type. It
means, that instead of an array of Cloud
, I’ll get an array of simple
JavaScript objects with primitive types. It works good enough until I use some
specific Date methods and properties of my Cloud.created_at
or
Cloud.updated_at
properties. Since TypeScript doesn’t do any type casting
itself, cloud.created_at
will be a string, not a Date object.
To fix it, I need manually convert JavaScript object to my TypeScript class.
I added a static method to Cloud
type to covert JavaScript to TypeScript
objects:
static fromObject(obj: CloudObject): Cloud {
let cloud = Object.create(Cloud.prototype);
return Object.assign(cloud, json, {
created_at: new Date(json.created_at),
});
}
All ‘magic’ is done by Object.assign function.
I introduced CloudObject interface just to verify types during the compile time and have my linter happy:
export interface CloudObject {
created_at: Date;
description: string;
name: string;
nodes: object;
updated_at?: Date;
id: string;
}