TypeScript Best Practices #2 – Use More Precise Type Than ‘string’

Featured on Hashnode
TypeScript Best Practices #2 – Use More Precise Type Than ‘string’

Introduction

The best thing about typescript is that you can always start by using just the basic features of the language. You don't have to use every advanced feature of it right from the beginning. You can incrementally learn and implement stricter typescript checks.

Defining a type

To get started, let's take an example. You can define the TypeScript type for product_1 as Object

const product_1: Object = {
  name: "MacBook Pro",
  color: 'grey',
  dateOfManufacture: '07-09-2021'
}

This is a valid TypeScript code. However, it doesn't help you much (other than giving you the satisfaction of adding the type for this variable). For better type checking, it would be better to define an interface for product_1.

interface IProduct {
  name: string;
  color: string;
  dateOfManufacture: string;
}

const product_1: IProduct = {
  name: "MacBook Pro",
  color: 'grey',
  dateOfManufacture: '07-09-2021'
}

This looks much better. Using the interface IProduct ensures that you (or someone on your team) doesn't accidentally assign any value that doesn't conform to IProduct.

For example, in the below code, the value of color property is set as 0. This would result in a typescript error.

const product_1: IProduct = {
  name: "MacBook Pro",
  color: 0, // ~~ Type 'number' is not assignable to type 'string'
  dateOfManufacture: '07-09-2021'
}

Now, if you have ever taken the Introduction of Algorithms class, you might have guessed the question you would ask yourself every time you have a naive solution.

Can I do better?

Yes, you can

But before that, let's see why you would want to do better.

So consider the below code snippet.

const product_1: IProduct = {
  name: "MacBook Pro",
  color: 'greyy',
  dateOfManufacture: '07-09-2021'
}

Again, this is a valid typescript code. product_1 is an object containing all the mandatory properties having values of the correct type i.e. string. However, there is something wrong here. By mistake, the developer spelled the color grey as greyy (an extra y in end). And that's okay. It happens!

We are only humans

Now, the question is can you write better typescript code to catch such errors before you run the code? Well, the answer is a big YES!

There are two ways to solve this.

Option 1: Use a union type

You can define a union type that would allow only a few specific values. Since Union type would be very specific about what values it can accept, typescript would be able to do more thorough checking.

type colorType = 'grey' | 'white' | 'rose gold'; 

interface IProduct {
  name: string;
  color: colorType;
  dateOfManufacture: string;
}

With union type in place, if you mistyped the spelling of the color property it would result in an error as shown below.

const product_1: IProduct = {
  name: "MacBook Pro",
  color: 'greyy', // ~~ Type '"greyy"' is not assignable to type 'colorType'
  dateOfManufacture: '07-09-2021'
}

Option 2: Define an enum

You can define an enum with all the possible values. The best thing about enums in typescript is that you can use it both as a type and as a value.

So you can define the enum COLORS like below and use it as a type in the interface IProduct

enum COLORS {
  GREY = 'grey',
  WHITE = 'white',
  ROSE_GOLD = 'rose gold'
}

interface IProduct {
  name: string;
  color: COLORS;
  dateOfManufacture: string;
}

In this approach, since you have defined the type of color as COLORS, you'll use the enum in the value as well. Directly using the string grey would also throw an error.

const product_1: IProduct = {
  name: "MacBook Pro",
  color: COLORS.GREY,
  dateOfManufacture: '07-09-2021'
}

Conclusion

In this article, we discussed that the domain of the values that a string type can accept, is huge. Whenever you have a variable of type string, you should ask yourself if you can use a narrower type than string. If it is possible, you can use any of the two options discussed above and ensure that you (and your colleagues) catch such potential bugs earlier during the development cycle.

Thank you for reading, hope you found this useful. Let me know in the comments below.

Happy coding!