DEV Community

Cover image for Template String Types as Discriminants in Typescript 4.5
Maina Wycliffe for This is Learning

Posted on • Originally published at mainawycliffe.dev

Template String Types as Discriminants in Typescript 4.5

Typescript 4.5 was just released and one of the features that stood out to me is the Template String Types as Discriminants. In this article, we are going to explore this new feature using rudimentary examples. In my last article, we covered using discriminated unions to write better types that are easy to narrow.

This is an extension of that but instead of having a concrete literal type, you can use a non-concrete literal type i.e. string, number, etc. instead as part of the template literal type, and Typescript will be able to use it as a discriminant.

In order to understand this feature, we are going to start by creating two types: SuccessType and ErrorType. They are going to represent possible responses for different operations we can perform in a computer system i.e. HTTP Request, FTP Request, IO Request, etc. So, if an HTTP request succeeds we get a SuccessType data, if it fails we get an ErrorType data.

For the two types, each will have a type property, which we can use to discriminate between the two types when they are used in a union i.e. ResponseType union. But Instead of using a concrete literal type, we will use a template string type instead.

This means that the resulting template literal type could be any string combined with Success or Error i.e. ${string}Success and ${string}Error. This will allow our success type to cover a number of possible operations like httpSuccess, ftpSuccess, etc. and the same goes for ErrorType.

type SuccessType = {
    type: `${string}Success`,
    data: Record<string, unknown>;
}

type ErrorType = {
    type: `${string}Error`,
    message: string;
}

type ResponseType = SuccessType | ErrorType;
Enter fullscreen mode Exit fullscreen mode
function processHTTPResponse(response: ResponseType) {
    // function body here
}
Enter fullscreen mode Exit fullscreen mode

In previous versions, Typescript won't be able to narrow down the type of the ResponseType union based on the type field, as shown below.

Template String Types as Discriminants in Typescript 4.5

But as of the latest version (4.5 and above), typescript is able to narrow the type of response to SuccessType as shown below.

Template String Types as Discriminants in Typescript 4.5

As you can imagine, this opens up a world of new possibilities by providing a literal type that is not concrete, typescript can discriminate between two unions as long as the field used to discriminate is contained in the string being compared to. Here is another rudimentary example:

type HttpOK = {
    status: `2${string}`;
    data: string;
}

type Http500 = {
    status: `5${number}`;
    message: string;
}

type Http300 = {
    status: `3${string}`;
    redirect: string;   
}

function processResponse(response: HttpOK | Http300 | Http500) {
    if(response.status === "200") {
        console.log(response.data);
    }

    if(response.status === "300") {
        console.log(response.redirect);
    }

    if(response.status === "500") {
        console.log(response.message);
    }
}
Enter fullscreen mode Exit fullscreen mode

Here is a link to Typescript Playground for the above code.

Conclusion

In this brief article, we looked at a new feature coming to Typescript v4.5 for using Template String Types as a discriminant. This allows us to build more versatile types by relying on a template pattern for the discriminant property rather than an exact string.

Discussion (3)

Collapse
scooperdev profile image
Stephen Cooper

In the final example I guess the following would also work as a use case that gets correctly discriminated. This is such a powerful feature!

if(response.status === "301") {
        console.log(response.redirect);
}
Enter fullscreen mode Exit fullscreen mode
Collapse
mainawycliffe profile image
Maina Wycliffe Author

Yeah, that would work as well