Repository navigation
4.0.0 — TS-type, performance, and compiler-strictness pass
A consolidated feat! that tightens the public type surface, hardens error objects at runtime, and makes the library compile cleanly under stricter TS settings. No new features — existing code that uses the factory API and treats IConwayError as read-only will keep working.
Breaking changes
IConwayErroris now fullyreadonly.rootContext,contextsChunk,feature,originalError,extendedParams, andemitare declaredreadonlyand the constructed instance isObject.freezed. Consumers that mutated these fields post-construction (e.g. reassigningerror.feature = "...") will get aTypeErrorin strict mode at runtime and a TS error at compile time.originalErrorandextendedParamsare nowT | undefined(always-present, possibly-undefined) instead of optional (?:). This is intentional for compatibility withexactOptionalPropertyTypes: true. Reading them is unchanged; spreading or property-presence checks ("originalError" in err) now always observe the key.OriginalErroris nowunknown. PreviouslyError | Record<string, unknown> | unknown. Callers passing odd values still work; downstream code that narrowed against the old union must re-narrow.isConwayErroris now brand-based, notinstanceof-based. Errors carry a non-enumerableSymbol.for("conway-errors:brand")property. Cross-realm errors and library-produced errors now both round-trip throughisConwayError. Anything that hand-constructed aConwayError-like object without going through the factory will no longer be recognised.package.json#exportsuses the nested conditional form ("."subpath withimport/require/types). Modern bundlers and Node ESM resolution are unaffected; very old toolchains that did not understand subpath exports may need an update.
Improvements
- Public type exports.
EmitFn,ExtendedParams,CreateErrorOptions,ErrorTypeConfig, andErrorFnOptionsare now exported from the package root. - Stricter publish gate.
prepublishOnlynow runstype-checkbefore lint/test/build, catching type regressions before they hit the registry. - Compile-time type tests. A new
index.test-d.ts(100 lines) asserts type-level guarantees alongside the runtime test suite. - Expanded runtime test suite. 28 tests covering branded paths, freeze semantics, brand-based recognition, and message-postfix behaviour.
- Cleaner constructor flow.
featureis set in the constructor rather than mutated afterwards — required for the freeze, and removes a footgun where the field briefly held"".
Migration
Most consumers need no changes. If you do any of these, adjust:
- Mutating
error.feature,error.extendedParams, etc. after construction → stop; pass the values through the factory. - Relying on
error instanceof ConwayErrorfrom outside the package → switch toisConwayError(error). - Type-narrowing on the old
OriginalErrorunion → narrow againstunknowninstead. exactOptionalPropertyTypes: trueusers who previously gotundefinedrejected when assigning tooriginalError/extendedParams→ those slots are now declaredT | undefined, so explicitundefinedis allowed.
Internals
- Bundle size unchanged (~1.3 kB gzipped main entry).
- Zero runtime dependencies preserved.