DEV Community

Cover image for 5 useful TypeScript tricks
Basile Bong
Basile Bong

Posted on • Edited on • Originally published at basilebong.com

5 useful TypeScript tricks

1. Create a type checking function

interface IDog{
   name:  string;
   age: number;
   kidFriendly: boolean;
}

interface ICat{
   name: string;
   age: number;
   activityLevel: number;
}

type Animal = IDog | ICat;

/** Is the animal a dog ? */
const isDog = (animal: Animal) : animal is IDog => (animal as IDog).kidFriendly !== undefined;

if(isDog(animal)){
   console.log(animal.kidFriendly);
}
Enter fullscreen mode Exit fullscreen mode

More information here:

2. Set all properties of an interface to optional

interface IDog{
   name: string;
   age: number;
   kidFriendly: boolean;
}

const dog : Partial<IDog> = {
   name: "Rex"
}
Enter fullscreen mode Exit fullscreen mode

3. Get the type of the parameters of a function

const walkDog = (dogName: string, distance: number) => { /** ... */ }

const params: Parameters<typeof walkDog> = ["Rex", 48];
Enter fullscreen mode Exit fullscreen mode

4. Use Setters and Getters

Setters and Getters also exist in plain JavaScript. Still, they are very useful in TypeScript (and other languages).

class Dog{
   private _name: string = "";

   get name(): string{
      return this._name;
   }

   /** Check the length of the name before setting it **/
   set name(newName: string){
      if(newName.length < 8) {
         throw new Error(`The dog's name needs at least 8 charachters`)
      }

      this._name = newName;
   }
}
Enter fullscreen mode Exit fullscreen mode

5. Optional chaining

Optional chaining has recently been added to JavaScript (ECMAScript 2020).

let cat?: ICat;  

/** With optional chaining **/
let animal = cat?.fur.length;

/** Without optional chaining **/
let cat = cat === null || cat === undefined ? undefined : car.fur.length;
Enter fullscreen mode Exit fullscreen mode

Top comments (13)

Collapse
 
hamishwhc profile image
HamishWHC

How does the isDog function work since .type is not a valid property? And how does JS know to set the private property .name in the setter instead of calling the setter again?

Collapse
 
shaegi profile image
Marvin Semmelroth • Edited

My guess would be that the example is not complete.
You could create an enum like

enum Animaltype = {
dog = "dog",
cat = "cat"
}

and adjust the Interfaces by creating animal as parentinterface:

interface Animal {
 type: AnimalType
}

interface IDog extends Animal {
type: AnimalType.dog
....
}

interface ICat extends Animal {
type: AnimalType.cat
....
}
Collapse
 
leob profile image
leob • Edited

I guess you're right, I also didn't understand how it worked, and I noticed how much code is needed just to determine if an animal is an IDog or an ICat ...

This seems so basic, but no, we need to write something like:

const isDog = (animal: Animal) : animal is Dog => animal.type === "dog";

I don't even understand the "animal is Dog" construct before the arrow, what is that? ... and now it seems that in fact we also have to add an enum to make it work :-)

I can't believe that we need this much boilerplate for something so trivial ... why doesn't TS simply let us write const isDog = animal is IDog; or something like that?

Thread Thread
 
shaegi profile image
Marvin Semmelroth

The concept is called typeguard and its basicly that you telling TS a condition under which an animal will be a dog since TS can't infer it sometimes by itself.

You could modify the example by writing something like:

enum Animaltype = {
dog = "dog",
cat = "cat"
}

interface BaseAnimal {
 type: AnimalType
}

interface IDog extends BaseAnimal {
type: AnimalType.dog
....
}

interface ICat extends BaseAnimal {
type: AnimalType.cat
....
}

type Animal = ICat | IDog

if you then have something beeing typed as animal a simple if-statement would be enough to determine the type

if(animal.type === AnimalType.dog) {
// all dog specific attributes should now be typesafe
}

Thread Thread
 
leob profile image
leob • Edited

Thanks, I vaguely remember type guards ... such a complex beast, Typescript, I've done one toy project with it, and yes you can produce some pretty elegant code if you put in the necessary effort, but it really requires an investment ... I'm still baffled that we have JS and then we put a typed language on top of it which is 5 times more complex than JS and takes at least 3 times longer to master, and all the while people are still disagreeing on its benefits.

Thread Thread
 
shaegi profile image
Marvin Semmelroth

IMO typescript once you know some of the pitfalls can become a super strong tool too determine bugs before you hit refresh without having too much overhead in typing. Its also great while refactoring since you see most of the bugs right away and don't need to search them.

Thread Thread
 
leob profile image
leob

Yes absolutely, it shines with refactoring and especially with autocomplete in an IDE like VSCode (you benefit from that even when you don't use TS but your libraries/imports do) ... and what I liked is that your code "documents itself" and that it makes you think a bit more thoroughly about code design.

Collapse
 
leob profile image
leob

I suppose that since that piece of code is within the scope of the setter it will assume that .name is the property, and not the setter itself?

Collapse
 
basilebong profile image
Basile Bong

I edited the setter/getter example. It will work properly and be more clear.

Collapse
 
shadowtime2000 profile image
shadowtime2000 • Edited

I believe setters and getters are already available in plain javascript.

Collapse
 
basilebong profile image
Basile Bong • Edited

Hi,
Indeed Setters and Getters also exist in plain JS. Note that optional chaining has also been recently added to JS.
Thanks for the comment, I will edit my post to make this clear!

Collapse
 
naderalfakesh profile image
Nader Alfakesh

Hi Basile thanks for sharing.
Can you explain the firsr example a little more.
It is very interesting.
Best regards..

Collapse
 
basilebong profile image
Basile Bong

Hi Nader,
I created a new post to make the concept of User-Defined Type Guards (showed in the first example) easier to understand. Let me know if you have any questions.