DEV Community

Ramu Narasinga
Ramu Narasinga

Posted on • Edited 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 me:

Hey, my name is Ramu Narasinga. I study large open-source projects and create content about their codebase architecture and best practices, sharing it through articles, videos.

I am open to work on an interesting project. Send me an email at ramu.narasinga@gmail.com

My Github - https://github.com/ramu-narasinga
My website - https://ramunarasinga.com
My Youtube channel - https://www.youtube.com/@thinkthroo
Learning platform - https://thinkthroo.com
Codebase Architecture - https://app.thinkthroo.com/architecture
Best practices - https://app.thinkthroo.com/best-practices
Production-grade projects - https://app.thinkthroo.com/production-grade-projects

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)