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.
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 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';
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))
Otherwise, the value in NEXT_PUBLIC_UPLOAD_TRANSPORT will be ‘database’ and it handled using otherwise:
.otherwise(async () => putFileInDatabase(file));
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.
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.