Skip to content

[BUG] fromPartial rejects null for optional fields #1186

Closed
@LuckyEden

Description

@LuckyEden

When using ts-proto via buf with useNullAsOptional=true, fields declared as optional float in your .proto schema generate TypeScript interfaces allowing null:

message Weight {
  string id = 1;
  string unit = 2;
  // value is optional
  optional float value = 3;
  string createdAt = 5;
  string updatedAt = 6;
}
export interface Weight {
  id: string;
  unit: string;
  /** value is optional */
  value?: number | null | undefined;
  createdAt: string;
  updatedAt: string;
}

However, fromPartial's signature only permits number | undefined for value, crashing when you pass null.

Reproduction Steps

  1. Create a buf.gen.yaml with ts-proto plugin and useNullAsOptional=true:

    version: v1
    
    plugins:
      - name: ts-proto
        path: ./node_modules/.bin/protoc-gen-ts_proto
        out: src/generated/test
        opt:
          - esModuleInterop=true
          - outputServices=grpc-js
          - env=node
          - strict=true
          - useNullAsOptional=true
          - outputClientImpl=false
  2. Define the message in your .proto file (as above).

  3. Run buf generate to emit .ts files.

  4. Attempt to call:

    import { Weight } from "./generated/test";
    
    const partial = { id: "abc", unit: "kg", value: null }; // A Prisma ORM result 
    const w = Weight.fromPartial(partial); // Type error: Argument of type '{ value: null; }' is not assignable...

Expected Behavior

Since the generated interface allows value to be null, fromPartial should also accept null:

declare function fromPartial<I extends DeepPartial<Weight>>(object: I): Weight;

should allow object.value to be null.

Actual Behavior

fromPartial only accepts number | undefined:

value?: (number | undefined);

Passing null yields a TypeScript compile error.

Workaround

Editing the generated helper types:

// before
type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined;

// after
type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined | null;

fixes the error, but is obviously not ideal.

Questions

  1. Is this a bug in ts-proto’s fromPartial generator, given useNullAsOptional=true?
  2. If not, is there a recommended configuration or flag to ensure fromPartial accepts null for optional scalar fields?
  3. Would a PR to include null in the built-in type union be acceptable?

Thank you for your help! 😃

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions