DEV Community

Cover image for Pulling Strings with Typescript
Philippe Poulard
Philippe Poulard

Posted on

Pulling Strings with Typescript

In the Typescript zoo, there are union types that are very helpful, specifically to narrow down strings :

type size = 'small' | 'medium' | 'large';
Enter fullscreen mode Exit fullscreen mode

This works well for known list of items, but for other types, one often use the common type string.

Could we do better ? Why should we do better ?

Let's start with some data :

{
    const madrid: string = 'Madrid';
    const spain: string = 'Spain';
    const localisation = spain;
}
Enter fullscreen mode Exit fullscreen mode

It's not clear whether the localisation has to be a city or a country, so let's try to define some type :

{
    type City = string
    const madrid: City = 'Madrid';
    type Country = string;
    const spain: Country = 'Spain';
    const localisation: Country = spain;
    const localisation2: Country = madrid; // 😵 oh no !!!
                                           // it passes...
    // well, Madrid is not a Country !
}
Enter fullscreen mode Exit fullscreen mode

Above, defining a type City doesn't help ; Typescript just takes this type as an alias to string, therefore it won't enforce anything, except our intention (that makes the answer to the question : why should we do better ?)

Could we do better ? Yes : even if you have an open list of values, you may define a type by examples :

{
    type City = 'London' | 'Paris' | '[any city]'
    const madrid: City = 'Madrid' as City;
    type Country = 'United-Kingdom' | 'France' | '[any country]';
    const spain: Country = 'Spain' as Country;
    const localisation: Country = spain;
    const localisation2: Country = madrid; // ❌ oh yes, it fails !!!
    // Typescript will say that a City
    // is not assignable to a Country
}
Enter fullscreen mode Exit fullscreen mode

What is nice, is that your code can either take any data source with valid types as well as hard-coded data like in the example above : writing 'Spain' as Country makes sense, 'Spain' as City wouldn't.

This is a technique that I use and abuse because it prevents putting a string in another string when they are semantically unrelated. And believe me, it saves me from lots of runtime errors !

And it works for numbers too :

/** Any HTTP port (other values are accepted
 * as long they are related to HTTP)
 */
type HttpPort = 80 | 8080 | 443 | 8443;
const port1: HttpPort = 8080; // ok, a known value
const port2: HttpPort = 8888 as HttpPort; // because I'm sure
Enter fullscreen mode Exit fullscreen mode

Top comments (0)