Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
April 11, 2022 11:18 pm GMT

Typescript Tip: Safer functions with branded types.

Imagine you have a function like this one:

interface Post {  id: number  title: string}export function getPosts(page: number): Post[] {  // perform some query to return posts from a database  // ...  // ...  return []}

getPosts accepts a page argument and retrieves posts from a data source.

Now, what if getPosts is used like this?

const posts = getPosts(-1);

Obviously That's incorrect because a page number can not be negative. A simple solution would be add a line like this one:

if(page < 0) throw Error('Page must be a positive number')`

But would not be nice if we receive a type error when we try to call the function with a negative number?

The problem here, is that the type number is too general for our function. number can be any number and we are expecting just a positive number.

We can create a type alias for it:

type PositiveNumber = number;

Although it makes our code more readable, using a simple alias doesn't solve the problem. Because we are still able to pass any number as an argument to getPosts().

This is when we can create a Branded Type.

Branded Types

When the base type is too general we can use this pattern.

type PositiveNumber = number & { __type: 'PositiveNumber' };

Here we are using an intersection between the base type (number) and an object with the __type property, this private property holds the brand type, and its used to differentiate it from a regular number.

We can rewrite our function to:

type PositiveNumber = number & { __type: 'PositiveNumber' };export function getPosts(page: PositiveNumber): Post[] {  // ...  return []}

Now if we try to call it like before, we're going to receive the error we expect.

const posts = getPosts(-1); // ^^^ Argument of type 'number' is not assignable to parameter of type 'PositiveNumber'.

Let's try with a valid number:

const posts = getPosts(2); // ^^^ Argument of type 'number' is not assignable to parameter of type 'PositiveNumber'.

Hmm, that's doesn't make sense , I'm sure 2 is a positive number.

We are still receiving the same error because we are still passing a number, not a PositiveNumber. Son wee need to explicitly say to the compiler that we are passing a PositiveNumber using the as keyword.

const posts = getPosts(2 as PositiveNumber); 

That will get rid of the error.

Now, what if we have a variable that we can't tell if it's a positive number or not?

const { page } = incomingRequest.body;  // here, page could be a positive or a negative number, so we can't use the `as` keyword because we can't be sure of what is the actual value;const posts = getPosts(page); 

To solve this we can use an assertion function that asserts page is an actual PositiveNumber

function assertsPositiveNumber(value: number): asserts value is PositiveNumber {  if(value < 0) throw new Error('Value must be a positive number');}

Now with this assertion, we can tell if page is a positive number or not.

const { page } = incomingRequest.body;  assertsPositiveNumber(page);const posts = getPosts(page); // at this point TypeScript know that `page` its a PositiveNumber

If you liked this tip, please, share it and hit the

Further Reading:


Original Link: https://dev.to/andersonjoseph/typescript-tip-safer-functions-with-branded-types-14o4

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To