Fix Bool deserialized as number in TS SDK fast path (#4596)

Fixes #4591

## Root Cause

The `isFixedSizeProduct` fast-path deserializer in `algebraic_type.ts`
maps `Bool` to `view.getUint8()`, which returns a **number** (0 or 1)
instead of a JavaScript **boolean**. The slow path (`reader.readBool()`)
correctly converts via `!== 0`.

This means any product type containing only fixed-size primitives
(bools, ints, floats) hits the fast path and returns numbers for boolean
fields. Products containing strings, arrays, or nested objects go
through the slow path and work correctly.

This explains the inconsistency in the issue: a flat `{ foo: bool }`
returns `{ foo: 1 }`, but adding a nested object pushes it to the slow
path where `foo` becomes `true` (though the nested bool still hits the
fast path within its own product).

## Fix

Special-case `Bool` in the fast-path code generation to emit:
```js
result.foo = view.getUint8(reader.offset) !== 0;
```
instead of:
```js
result.foo = view.getUint8(reader.offset);
```

One-line change in the ternary within `makeDeserializer`.

Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
Co-authored-by: Zeke Foppa <196249+bfops@users.noreply.github.com>
This commit is contained in:
clockwork-labs-bot
2026-03-10 16:51:25 -04:00
committed by GitHub
parent 354dd45499
commit c7ef2346a2
@@ -535,7 +535,11 @@ const view = reader.view;
${ty.elements
.map(({ name, algebraicType: { tag } }) =>
tag in primitiveJSName
? `\
? tag === 'Bool'
? `\
result.${name} = view.getUint8(reader.offset) !== 0;
reader.offset += 1;`
: `\
result.${name} = view.get${primitiveJSName[tag as JSPrimitives]}(reader.offset, ${primitiveSizes[tag] > 1 ? 'true' : ''});
reader.offset += ${primitiveSizes[tag]};`
: `result.${name} = reader.read${tag}();`