Skip to content

TS: add Symbol.dispose / Symbol.asyncDispose to Tx and Rx #309

@fasterthanlime

Description

@fasterthanlime

Context

The TypeScript runtime has no equivalent of Rust's Drop, so server-side Tx (and any other channel handle the user holds) must be closed explicitly. Forgetting to do so hangs the peer's Rx iteration waiting for end-of-stream — see 4441c73 where streaming test handlers had to add explicit output.close() calls.

Proposal

Add [Symbol.dispose]() (and [Symbol.asyncDispose]() where appropriate) to Tx and Rx so callers can opt into deterministic, scope-based cleanup with using:

async generate(count: number, output: Tx<number>): Promise<void> {
  using out = output;
  for (let i = 0; i < count; i++) await out.send(i);
}

Semantics:

  • [Symbol.dispose]() on Tx calls this.close().
  • [Symbol.dispose]() on Rx releases the receiver (closes the local channel, drops it from the registry).
  • Channels that need to outlive the method call simply don't use using — current explicit close() behavior is preserved.

Notes

  • using is lexical sugar over try/finally, not a finalizer — so leaking the handle out of scope still works the same as today (no auto-close).
  • Symbol.dispose is polyfilled by TS (Symbol.dispose ??= Symbol.for("Symbol.dispose")) so no runtime gating needed.
  • There's a TODO comment already at typescript/packages/vox-core/src/channeling/tx.ts:240 noting this was deferred for target-version reasons; tsgo / current targets should be fine now.

Related

  • 4441c73 — workaround making handlers explicit

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions