1

The Truth About TypeScript Types

 1 year ago
source link: https://blog.bitsrc.io/the-truth-about-typescript-types-c2585a43d85c
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

The Truth About TypeScript Types

TypeScript is a great addition to the JavaScript ecosystem, but it isn’t like other typed languages.

0*iRVVgKY9K-5fd07R

In Java and C# all models and functional code must be written as a class. It is pretty verbose and prescriptive to write all that boilerplate code, constructing a class just to add a callback.

These languages use a nominal typing system where everything must have a declared type and classes are the preferred typing system for these languages. If everything is a class, then everything is typed.

Equivalence of types is not defined by their structure, but by the explicit declaration or naming of the type. Two types with different names are always considered distinct, even if they have the same fields.

The following two Java classes are not the same, although they have the same structure. It is exactly like we would expect from Java, and also in the real world. A person and a fish are not the same after all.

public class Fish { 
public void swim() {
System.out.println(“I’m swimming!”);
}
} public class Person {
public void swim() {
System.out.println(“I’m swimming!”);
}
}

But what about TypeScript? This uses a duck typing system, which defines types in terms of behaviour instead of definition.

So the two types, Fish and Person, in the above example would be considered the same. In other words, TypeScript types are not always unique! TypeScript has a quirk or maybe we can call it a feature, that makes this anomaly quite logical in practice.

class Person {
public weight: number;
constructor(weight:number){
this.weight = weight;
}
swim(){}
}class Fish{
public weight: number;
constructor(weight:number){
this.weight = weight;
}
swim(){}
}const fish:Person = new Fish(50);
console.log(fish instanceof Fish); // TRUE
console.log(fish instanceof Person); // FALSE

See this typescript example above. TypeScript is happy for us to declare that the fish variable is actually a Person type. Yeah I know right. But then during runtime, as shown in the console.log statement, the JavaScript interpreter knows better, namely that it is an instance of the Fish class.

So what is it?

Well, it is an instance of the Fish class of course. TypeScript just allows us to type it as an equivalent type.

If we would add even a single parameter height to the Person class, this code would break as we see in the screenshot below.

1*78WxSq1Ka1T28x_EvCAJMA.png

Not recommended to mix and match types like this.

But then we can fix it by defining the fish variable as a union type. Our variable can be either a Person or a Fish. Obviously it isn’t really recommended to use a union type like this.

const fish:Person | Fish = new Fish(50);

Any, unknown and never types

For lazy developers who like shortcuts, TypeScript has the any type. When we use this type we tell the compiler not to bother with it, as we really couldn’t be bothered to type our variables.

A bit less indifferent is the unknown type. We can use it when we don’t know what we can expect and are unfamiliar with generics. To be able to do anything with an unknown type we can use type-guards like in the example below.

const unknownVar:unknown = 9;
if(typeOf unknownVar === 'number'){
let myNumber:number = unknownVar;
}

This type-guard shows that we are at least a little careful in dealing with our types.

The never type is for a function that never returns. It instead is for functions that throw errors or keeps running forever. We can’t even return any from a never function.

This is different from a function that returns void, which means the absence of any type. Only null can be assigned to void. Normally these are functions that return without a value.

Runtime types

TypeScript doesn't have any runtime type support (apart from enums). When your TypeScript is compiled to JavaScript, all the type information that you so meticulously added is stripped out.

This makes it logical that types with different names, but the same structure are considered the same.

In most instances, this doesn’t really matter. Type introspection is most often used at a library or framework level, we can do without type-based pattern matching as we find in Rust, and serialization of data doesn’t require strict types in JavaScript.

When type checking on runtime is needed, a library like Joi can be used, or class-based decorators. These options are fairly verbose and not always the best solution.

When we really need runtime type support, we can use ttypescript, a custom compiler that supports transform plugins. Combined with other modules, it can provide compiled in runtime type support.

On the other hand, if you are feeling adventurous, it is possible to disable a lot of the type-checking features in TypeScript altogether. By editing tsconfig we can disable many of the type-checking features. Although it isn’t always recommended, this is a level of flexibility that languages like Java do not offer.

1*0urcXRHyRcqC89z4ddPGWw.png

Typescript allows type-checking features to be turned off. From tsconfig reference

TypeScript is mature and feature-rich, it allows us to write code that is self-documenting and safer than plain JavaScript, at the small cost of marginally more verbose code and increased compile time.

Even without runtime type checking, it helps prevent the most common bugs. I would recommend everyone to read the Typescript handbook to really get to know this language.

Thank you for reading all the way to the end, I hope you found this article interesting. Please support me by following me here on Medium, on Twitter or connecting on LinkedIn.

Bit: Build Better UI Component Libraries

Say hey to Bit. It’s the #1 tool for component-driven app development.

With Bit, you can create any part of your app as a “component” that’s composable and reusable. You and your team can share a toolbox of components to build more apps faster and consistently together.

  • Create and compose “app building blocks”: UI elements, full features, pages, applications, serverless, or micro-services. With any JS stack.
  • Easily share, and reuse components as a team.
  • Quickly update components across projects.
  • Make hard things simple: Monorepos, design systems & micro-frontends.

Try Bit open-source and free→

1*p3UFa6xnmmbrkTzfRm_EmQ.png

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK