Skip to content

fix(typegen): type TRANSFORM_MAP callbacks against actual method types#33

Merged
johncarmack1984 merged 2 commits into
mainfrom
john/type-transform-map
May 25, 2026
Merged

fix(typegen): type TRANSFORM_MAP callbacks against actual method types#33
johncarmack1984 merged 2 commits into
mainfrom
john/type-transform-map

Conversation

@johncarmack1984
Copy link
Copy Markdown
Collaborator

Summary

The TRANSFORM_MAP generator emits per-method transform callbacks like (v) => v.map((i) => i). Without parameter annotation, those v/i/response identifiers trip noImplicitAny in strict-mode consumers, and consumers have no clean place to silence it (the whole file is auto-generated).

Approach

Keep the outer parameter unknown so the callback remains contravariantly assignable to the runtime's TransformFn = (value: unknown) => unknown. Narrow once inside the body via const t = v as <method-type>. The runtime expression already references that bound identifier, so the typed binding satisfies strict mode without weakening the runtime contract.

Before:

export const TRANSFORM_MAP = {
  airports: {
    get_airport_bounds: {
      args: [null],
      eventArgs: [null],
      result: (v) => v == null ? v : v.map((i) => i),
    },
  },
};

After:

export const TRANSFORM_MAP = {
  airports: {
    get_airport_bounds: {
      args: [null],
      eventArgs: [null],
      result: (v: unknown) => {
        const t = v as [number | null, number | null, number | null, number | null] | null;
        return t == null ? t : t.map((i) => i);
      },
    },
  },
};

The type for t is rendered from the same DataType the generator already had on hand (Deserialize-phase for args, Serialize-phase for event args and results -- matching what the IPC bridge actually passes through the callback). Channel handlers get the same treatment with the inner response parameter typed against the channel's payload DataType.

Test plan

  • cargo build -p taurpc clean
  • Regenerated bindings on a downstream consumer (fltsci); the prior 10 TS7006: Parameter 'v' implicitly has an 'any' type errors clear without any consumer-side @ts-ignore or tsconfig escape hatches
  • No runtime change -- only the emitted TypeScript shape changes
  • Draft for now -- pin gets validated end-to-end via the fltsci specta rc.25 bump branch before un-drafting

Notes

The runtime types (TransformFn, MethodTransform, TransformMap in src/index.ts) intentionally stay at (value: unknown) => unknown -- generators and hand-written consumers should both be allowed to widen to that shape.

The generator emits per-method transform callbacks like
`(v) => v.map((i) => i)` inside TRANSFORM_MAP. Without parameter
annotation those v / i / response identifiers trip noImplicitAny in
strict-mode consumers.

Keep the outer parameter unknown -- preserves contravariant
assignability to the runtime's TransformFn = (value: unknown) =>
unknown -- and narrow once via `const t = v as <method-type>`
inside the callback body. The runtime expression already references
`t`, so the typed binding satisfies strict-mode without adding casts
at the consumer side or weakening the runtime contract.

Method input types are rendered from the same DataType the generator
already has (Deserialize-phase for args, Serialize-phase for event
args and results -- matching what the IPC bridge actually passes
through the callback). Channel handlers get the same treatment with
the inner `response` parameter typed against the channel's payload
DataType.
@johncarmack1984 johncarmack1984 marked this pull request as ready for review May 25, 2026 02:33
@johncarmack1984 johncarmack1984 merged commit aa9075c into main May 25, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant