DEV Community

thinkThroo
thinkThroo

Posted on

ts-pattern usage in Documenso source code

In this article, we analyse the ts-pattern usage in Documenso source code, but before that, let’s learn what a ts-pattern library is.

ts-pattern

ts-pattern is an exhaustive Pattern Matching library for TypeScript with smart type inference. Write better and safer conditions. Pattern matching lets you express complex conditions in a single, compact expression. Your code becomes shorter and more readable. Exhaustiveness checking ensures you haven’t forgotten any possible case.

import { match, P } from 'ts-pattern';
type Data =
 | { type: 'text'; content: string }
 | { type: 'img'; src: string };
type Result =
 | { type: 'ok'; data: Data }
 | { type: 'error'; error: Error };
const result: Result = ;
const html = match(result)
 .with({ type: 'error' }, () => <p>Oups! An error occured</p>)
 .with({ type: 'ok', data: { type: 'text' } }, (res) => <p>{res.data.content}</p>)
 .with({ type: 'ok', data: { type: 'img', src: P.select() } }, (src) => <img src={src} />)
 .exhaustive();
Enter fullscreen mode Exit fullscreen mode

This example is pretty self-explanatory. Now that we understand a basic example of how ts-pattern works. Let’s apply this to the code found in Documenso.

match usage in Documenso source code.

In Documenso source code, there is a file named upload/put-file.ts and you will find this below code at line 48.

import { match } from 'ts-pattern';
import { env } from 'next-runtime-env';
export const putFile = async (file: File) => {
 const NEXT_PUBLIC_UPLOAD_TRANSPORT = env('NEXT_PUBLIC_UPLOAD_TRANSPORT');
return await match(NEXT_PUBLIC_UPLOAD_TRANSPORT)
 .with('s3', async () => putFileInS3(file))
 .otherwise(async () => putFileInDatabase(file));
};
Enter fullscreen mode Exit fullscreen mode

match is applied against a variable named NEXT_PUBLIC_UPLOAD_TRANSPORT. Based on the example above, you

pass a parameter to match and run a check against it using with. In the example from documentation above, it was based on type and data, but here in this code snippet from Documenso, it is a different story.

with is checked against a string — ‘s3’. At this point, I just wanted to find out what is expected as value for the variable Next_PUBLIC_UPLOAD_TRANSPORT. I searched for this variable — NEXT_PUBLIC_UPLOAD_TRANSPORT across the codebase and found its type definition in a file named process-env.d.ts. This file is in package named tsconfig. Documenso is a monorepo and contains workspaces inside apps folder and packages inside packages folder.

NEXT_PUBLIC_UPLOAD_TRANSPORT?: 'database' | 's3';
Enter fullscreen mode Exit fullscreen mode

NEXT_PUBLIC_UPLOAD_TRANSPORT accepts only two string literals — ‘database’ or ‘s3’. Now it makes sense, you see. This is why you have a check against ‘s3’ string to call a function named putFileInS3.

.with('s3', async () => putFileInS3(file))
Enter fullscreen mode Exit fullscreen mode

Otherwise, the value in NEXT_PUBLIC_UPLOAD_TRANSPORT will be ‘database’ and it handled using otherwise:

.otherwise(async () => putFileInDatabase(file));
Enter fullscreen mode Exit fullscreen mode

This reminds me of the .exhaustive() function. ts-pattern documentation says this about exhaustive function —



Exhaustiveness checking ensures you haven’t forgotten any possible case.

I think using .exhaustive() when you are dealing with a match against an object, like the one provided in documentation example, makes sense. Since this variable NEXT_PUBLIC_UPLOAD_TRANSPORT accepts only two string literals — ‘database’ or ‘s3’, there’s only string and no object to match against, that’s why there is no need for using .exhaustive(), instead .otherwise is used.

About us:

At Thinkthroo, we study large open source projects and provide architectural guides. We have developed reusable Components, built with tailwind, that you can use in your project.

We offer Next.js, React and Node development services.

Book a meeting with us to discuss your project.

Image description

References:

  1. https://github.com/documenso/documenso/blob/main/packages/lib/universal/upload/put-file.ts#L51

  2. https://www.npmjs.com/package/ts-pattern

  3. https://github.com/documenso/documenso/blob/main/packages/tsconfig/process-env.d.ts#L25

Top comments (0)