Skip to content

[Feature] Codebase-wide null/undefined disambiguation rule (Option<X> for public API) #258

Description

@pathosDev

Size / Priority

  • Size: M — many APIs touched; not a single PR.
  • Category: C.2 Simplifications & DRY (consistency).
  • Risk: medium — public-API-shape change for some types.

Affected files

  • Across the codebase — public APIs that return one of: X | null, X | undefined, or Option<X>.

Background

The codebase mixes three "no value" idioms:

  • null — explicit "nothing".
  • undefined — absent / not set.
  • Option<X> — custom Maybe-like wrapper.

Inconsistent across APIs. Same conceptual "find me X" returns each variant at different call sites. Some examples:

  • ActorContext.child(name): Option<ActorRef> — uses Option.
  • Cache.get<V>(key): Promise<V | undefined> — uses undefined.
  • Cluster.currentLeader(): Option<Member> — uses Option.
  • LookupResult.value: T | null — uses null.

This is a recurring point of confusion in the README + onboarding.

Target — codebase rule

Decide one shape per use case:

  • Option<X> for cases where "absent" is a frequent + meaningful result that callers should explicitly handle (e.g., resolving a path).
  • X | undefined for optional values where the caller will often skip if missing (e.g., cache lookup).
  • Avoid null — pick one of the above per case.

Document the rule. Migrate inconsistent sites.

Migration plan

This is a multi-PR cleanup:

  1. Audit — every public API returning one of these shapes. Decide target shape per API.
  2. Per-PR — migrate ~5-10 APIs at a time.
  3. Deprecation period — keep old signatures with @deprecated for a release.
  4. Removal — remove deprecated alternatives.

Integration / risk

  • Public API changes — semver caveat. Pre-1.0 is acceptable; document in CHANGELOG.
  • Option polyfill — keep the existing Option type; expand documentation.
  • Type signature ripple — callers that destructure or pattern-match may need updates.

Test plan

  1. Per-API: regression on type + value.
  2. TypeScript strict: noUncheckedIndexedAccess + strictNullChecks should compile.
  3. Documentation: each API's JSDoc states the chosen shape.

Acceptance criteria

  • Codebase rule documented (in CONTRIBUTING.md or equivalent).
  • Catalog of APIs needing migration.
  • Phased migration with CHANGELOG entries.
  • Old shapes deprecated with @deprecated + migration note.
  • CHANGELOG entry per phase.

Pre-implementation note

This is the biggest C.2 item — significant cleanup. Worth doing before 1.0, painful after.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestpriority: lowNice-to-have / niche / demand-driven

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions