Closed
Description
There is no compile error in const a: ProtoA = new ProtoB()
if the fields in ProtoA
are a subset of the fields in ProtoB
.
example.proto
syntax = "proto3";
message Foo {
int32 foo = 1;
}
message NotFoo {
int32 foo = 2; // Different tag number
}
// Foo with an extra field
message FooAndBar {
int32 foo = 1;
int32 bar = 2; // Extra field
}
example.ts
import { Foo, FooAndBar, NotFoo } from "./example_pb.js";
// Unsafe - No compile time error
const a0: Foo = new FooAndBar();
const a1: Foo = new NotFoo();
const a2: NotFoo = new Foo();
const a3: NotFoo = new FooAndBar();
// Good - compile time error
const a4: FooAndBar = new Foo(); // Property 'bar' is missing in type 'Foo' but required in type 'FooAndBar'.
const a5: FooAndBar = new NotFoo(); // Property 'bar' is missing in type 'NotFoo' but required in type 'FooAndBar'.
// This also affects function parameters
function example(foo: Foo) { }
example(new NotFoo()); // Unsafe - No error
An example fix would be adding a dummy private variable to to every generated proto. TypeScript doesn't output any code when compiling this, so there should be no runtime implications (Playground Link).
Relevant TypeScript docs:
When an instance of a class is checked for compatibility, if the target type contains a private member, then the source type must also contain a private member that originated from the same class.
export class Foo extends Message<Foo> {
private unused: any;
// Existing generated code...
}
// Good - Compile time error
// Type 'FooAndBar' is not assignable to type 'Foo'.
// Types have separate declarations of a private property 'unused'.
const a0: Foo = new FooAndBar();
Metadata
Assignees
Labels
No labels
Activity