Devansh Jethmalani Profile picture
Jan 3, 2022 โ€ข 14 tweets โ€ข 6 min read โ€ข Read on X
๐ŸŽ New Year's Gift for Y'all

โ“ `@โ€‹sthir/predicate` โ€” An eDSL to write typed predicates

๐Ÿง™๐Ÿปโ€โ™‚๏ธ Write your logical expression in a JS-like eDSL and get the typed predicate inferred.

๐Ÿ”—

๐Ÿ‘‡๐Ÿป Let me explain...github.com/devanshj/sthirโ€ฆ
We often write predicates, for example while filtering an array. But its type (as in `x is NarrowedX`) doesn't get inferred... Image
Moreover TypeScript is a little conservative, if you were writing this in JavaScript you won't write `"a" in x`, you'd simply write `typeof x.a === "string"`, wouldn't you? Image
With `@โ€‹sthir/predicate` you can simply import `p` and write the predicate...

๐Ÿ’†๐Ÿปโ€โ™‚๏ธ in JS-like DSL
๐Ÿ’ช๐Ÿป with autocompletions
๐Ÿฅต and the typed predicate gets inferred automatically!
๐Ÿ‘‰๐Ÿป Try it yourself tsplay.dev/wEGZgm
And you know what's the best part? With you can use the macro version `@โ€‹sthir/predicate/macro` with `babel-plugin-macro` (thanks to @kentcdodds) for zero runtime overhead.

If you use the macro version in the above code, it'll get transformed to this in build-time! ๐Ÿค  Image
You can also use the predicate in any other places that affect the control-flow analysis, for example in an `if` statement...

And that too would be inlined with the macro

tsplay.dev/mZbkJmImage
Image
Image
And I see ya'll get bummed here on twitter when TypeScript doesn't infer the predicate and doesn't narrow the types. Let's look at a few examples and see how `@โ€‹sthir/predicate` fixes it ๐Ÿ‘‡๐Ÿป
๐Ÿค” Problem: x.com/wcandillon/staโ€ฆ

๐Ÿ˜ Solved: tsplay.dev/NddqyN

Now there is such a library, @wcandillon ๐Ÿ˜Ž Image
๐Ÿค” Problem: x.com/addaleax/statuโ€ฆ

๐Ÿ˜ Solved: tsplay.dev/NVgGvm

@addaleax I hope this makes you love TS even more! ๐Ÿ˜ Image
๐Ÿค” Problem: x.com/AdamRackis/staโ€ฆ

๐Ÿ˜ Solved: tsplay.dev/w2EJYW

There you go @AdamRackis (not stupid for asking that question but still stupid for thinking it was a great decision to make `Promise` non-monadic ๐Ÿ˜›) Image
That's it folks, enjoy!

If you think `@โ€‹sthir/predicate` is dope, don't forget to RT to share it with your friends ๐Ÿคช
cc @typescript @drosenwasser @SeaRyanC Next time someone complains about not inferring typed predicates send them here ๐Ÿ‘†๐Ÿป๐Ÿ˜๐Ÿ˜Ž
Also I forgot to pitch how `@โ€‹sthir/predicate` makes your code more type-safe than the code that doesn't use it ๐Ÿ‘‡๐Ÿป๐Ÿ‘ฎ๐Ÿปโ€โ™‚๏ธ

@threadreaderapp unroll

โ€ข โ€ข โ€ข

Missing some Tweet in this thread? You can try to force a refresh
ใ€€

Keep Current with Devansh Jethmalani

Devansh Jethmalani Profile picture

Stay in touch and get notified when new unrolls are available from this author!

Read all threads

This Thread may be Removed Anytime!

PDF

Twitter may remove this content at anytime! Save it as PDF for later use!

Try unrolling a thread yourself!

how to unroll video
  1. Follow @ThreadReaderApp to mention us!

  2. From a Twitter thread mention us with a keyword "unroll"
@threadreaderapp unroll

Practice here first or read more on our help page!

More from @devanshj__

Mar 20, 2023
I made a runtime type checker and here's why I think it's cool...npm.im/@sthir/runtimeโ€ฆ
I'll also compare it with zod where applicable as it seems to be the most popular solution and my TL keeps hyping it.

1. Negligible Size

baseline: 137B
sthir: 1250B (ร—9 bigger, 1750B without tree-shaking)
zod: 10570B (ร—77 bigger, same without tree-shaking) https://bundlejs.com/?text=%22const+isUser+%3D+x+%3D%3E%5Cn++typeof+x+%3D%3D%3D+%5C%22object%5C%22+%26%26+x+%21%3D%3D+null+%26%5Cn++typeof+x.name+%3D%3D%3D+%5C%22string%5C%22+%26%26%5Cn++typeof+x.email+%3D%3D%3D+%5C%22string%5C%22+%26%26+x.email.includes%28%5C%22%40%5C%22%29%5Cn%5Cnconsole.log%28isUser%28%7B+name%3A+%5C%22Devansh%5C%22%2C+email%3A+%5C%22foo%5C%22+%7D%29%29%22
https://bundlejs.com/?q=%28import%29https%3A%2F%2Funpkg.com%2F%40sthir%2Fruntime-checker%2Fdist%2Fsthir-runtime-checker.esm.js&treeshake=%5B*+as+t%5D&text=%22const+isUser+%3D+x+%3D%3E%5Cn++t.is%28x%2C+t.object%28%7B%5Cn++++name%3A+t.string%2C%5Cn++++email%3A+t.then%28t.string%2C+t.predicate%28s+%3D%3E+s.includes%28%5C%22%40%5C%22%29%29%29%5Cn++%7D%29%29%5Cn%5Cnconsole.log%28isUser%28%7B+name%3A+%5C%22Devansh%5C%22%2C+email%3A+%5C%22foo%5C%22+%7D%29%29%22
https://bundlejs.com/?q=%28import%29https%3A%2F%2Funpkg.com%2Fzod%2Flib%2Findex.mjs&treeshake=%5B*+as+z%5D&text=%22const+isUser+%3D+x+%3D%3E%5Cn++z.object%28%7B%5Cn++++name%3A+z.string%28%29%2C%5Cn++++email%3A+z.string%28%29.refine%28s+%3D%3E+s.includes%28%5C%22%40%5C%22%29%29%5Cn++%7D%29.safeParse%28x%29.success%5Cn%5Cnconsole.log%28isUser%28%7B+name%3A+%5C%22Devansh%5C%22%2C+email%3A+%5C%22foo%5C%22+%7D%29%29%22
2. Lazy Parsing hence Performant

case 1: validation (bail after 1 error)
case 2: partial parse (bail after 10 errors)
case 3: full parse
(links in alt text)

zod doesn't have a lazy "on demand" parser so it does a wasteful full parse in case (1) & (2) too. https://jsperf.app/qadoma
https://jsperf.app/pisuzi
https://jsperf.app/kukuka
Read 7 tweets
Mar 19, 2022
Interviewer: Map an array
Me: xs.flatMap(x => [f(x)])

Interviewer: Ugh okay... How about filtering an array
Me: xs.flatMap(x => f(x) ? [x] : [])

Interviewer: ... concat concat two arrays
Me: [as, bs].flatMap(x => x)
Interviewer: SPLICE. Like xs.splice(n, m, ...a)?

Me: xs.flatMap((x, i) =>
0 <= i && i <= n - 1 ? [x] :
n <= i && i <= n + m ? []
i === n + m + 1 ? [a, x] :
[x]
)
Interviewer: OKAY NOW MAKE A SANDWICH WITH FLATMAP

Me: *starts typing*

Interviewer: DEVANSH STOP YOU CAN'T DO THAT

Me: Just checking you never know what you can do with >>== ;P
Read 4 tweets

Did Thread Reader help you today?

Support us! We are indie developers!


This site is made by just two indie developers on a laptop doing marketing, support and development! Read more about the story.

Become a Premium Member ($3/month or $30/year) and get exclusive features!

Become Premium

Don't want to be a Premium member but still want to support us?

Make a small donation by buying us coffee ($5) or help with server cost ($10)

Donate via Paypal

Or Donate anonymously using crypto!

Ethereum

0xfe58350B80634f60Fa6Dc149a72b4DFbc17D341E copy

Bitcoin

3ATGMxNzCUFzxpMCHL5sWSt4DVtS8UqXpi copy

Thank you for your support!

Follow Us!

:(