is-kit Reached 100 Stars β­πŸŽ‰ Here’s What Changed Since 50 A developer's open-source TypeScript type-guard library, is-kit, has reached 100 GitHub stars, up from 50, after adding property refinement helpers (refineKey, refineDefinedKey, refineIndex) and an exhaustive discriminated-union API in v1.15.0. The library, used in a production TypeScript application serving over 100,000 users, also surfaced a type-inference edge case in Effect-TS's Effect library through a real-world use case. Hoi hoi YAY is-kit https://github.com/nyaomaru/is-kit just reached 100 GitHub stars⭐ πŸŽ‰πŸŽ‰πŸŽ‰ When it reached 50 stars, I wrote about how we use it in a production TypeScript application serving more than 100,000 users. πŸ‘‡ I could write the same story again. But that would be boring. 😹 A lot has happened since then. The library gained new APIs , some existing APIs became stricter , I started using it in more of my own OSS projects , and one real-world use case even exposed a type inference edge case in Effect https://github.com/Effect-TS/effect . So this time, instead of explaining the production adoption again, I want to look at: is-kit outside the original production application Effect.catchIf Let's dive in πŸ”§ At 50 stars, the biggest thing I wanted to show was that is-kit https://github.com/nyaomaru/is-kit was not only a toy project. It was already being used in a real production application. πŸš€ The application had repeated runtime checks like typeof value === "string"; typeof value === "number"; value === null || value === undefined; and several larger user-defined type guards for things like HTTP errors, literal unions, arrays, API values, and plain objects. The interesting part was not that is-kit made those checks shorter. The interesting part was that it gave them one reusable shape . Small guards could be composed. Application-owned helpers could sit between the library and feature code. And the result could still participate in normal TypeScript control flow. That part has not changed. But since 50 stars, the library itself has moved quite a bit. πŸ‘€ One thing I kept running into was this. I already have a good type guard. I just want to apply it to one property. For example js declare const input: unknown; Maybe I already know how to validate a string js import { isString } from "is-kit"; But now I want to express "This object has a name property, and that property is a string." That sounds simple, but there are actually a few different cases. A required property is not the same as an optional property . An array index is not the same as an object property . And an optional property that becomes known to be defined should narrow differently from one that is still optional . So is-kit added three property refinement helpers: refineKey refineDefinedKey refineIndex The idea is simple Take a type guard you already trust and lift it onto a property or array element. js import { isString, refineKey } from "is-kit"; const hasStringName = refineKey "name", isString ; Now the string guard is reusable at a deeper level instead of being rewritten inside another custom predicate. This is a small API, but I like it because it follows the same design goal as the rest of is-kit . Do not build one giant validator. Build small checks that can be reused in normal TypeScript code . discriminatedUnion Got Much More Serious The biggest addition since the 50-star article is probably the exhaustive discriminated union API introduced in v1.15.0 . Consider a common TypeScript type type Result = { ok: true; value: string } | { ok: false; error: string }; At runtime, validating this is not difficult. You can check ok , then validate the corresponding fields. But there is another question Can TypeScript verify that the validator itself covers the whole union? That is where discriminatedUnion comes in. js import { discriminatedUnion, isString, oneOfValues, typedStruct } from "is-kit"; type Result = { ok: true; value: string } | { ok: false; error: string }; const resultUnion = discriminatedUnion