is-kit Passes 100 Stars With New APIs, Stricter Guards, and a Merged Effect Fix
The NoInfer pattern matters beyond this library: any generic API that takes a predicate should stop the predicate's input type from redefining an already-inferred type parameter. And is-kit's milestone is a concrete example that small, composable guards can gain traction without growing into a schema framework.
is-kit, a small TypeScript library for composable runtime type guards, passed 100 GitHub stars. The 50-star milestone was built around production use in an app serving more than 100,000 users. Between 50 and 100, the library added refineKey, refineDefinedKey, and refineIndex, which apply an already-trusted guard to an object property or array element. v1.15.0 also introduced an exhaustive discriminatedUnion builder that checks at compile time for missing branches, extra branches, incompatible guards, and incomplete discriminant tuples, so a guard cannot silently lag behind a changing union type.
Stricter behavior came from fixes to recordOf literal-key narrowing, native Error brand checks, arrays with overridden iterators, exact struct validation, symbol-keyed struct schemas, and cross-realm struct schemas. Package tests now run against the published package from ESM and CommonJS TypeScript consumers, with Deno/JSR smoke tests as well.
A user report produced the most interesting result: combining is-kit's unknown-based refinement with Effect.catchIf could widen the error channel to unknown. The report led to a merged Effect PR that changed the refinement input to Predicate.Refinement<NoInfer<E>, EB>, with the same fix applied to Channel and Stream. is-kit also began showing up in other OSS projects, including changelog-bot, where define and oneOfValues keep small predicates composable.
A refinement written over unknown can become an inference hazard inside generic APIs; the merged Effect fix shows that a predicate's input type should not participate in inferring a type parameter the API already constrains. That is a general lesson for TypeScript library design, not a one-off patch.
The exhaustive discriminatedUnion attacks a real failure mode: TypeScript types evolve while hand-written guards silently lag. Moving coverage checks into the builder is worth more than the runtime validation alone.
External use carries the most useful evidence in this milestone: users filed issues, compared validators, and triggered a cross-library bug report. That kind of use is exactly what internal testing cannot produce.
Congratulations! The type-narrowing part was explained quite clearly.