You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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";
messageFoo {
int32foo=1;
}
messageNotFoo {
int32foo=2; // Different tag number
}
// Foo with an extra fieldmessageFooAndBar {
int32foo=1;
int32bar=2; // Extra field
}
example.ts
import{Foo,FooAndBar,NotFoo}from"./example_pb.js";// Unsafe - No compile time errorconsta0: Foo=newFooAndBar();consta1: Foo=newNotFoo();consta2: NotFoo=newFoo();consta3: NotFoo=newFooAndBar();// Good - compile time errorconsta4: FooAndBar=newFoo();// Property 'bar' is missing in type 'Foo' but required in type 'FooAndBar'.consta5: FooAndBar=newNotFoo();// Property 'bar' is missing in type 'NotFoo' but required in type 'FooAndBar'.// This also affects function parametersfunctionexample(foo: Foo){}example(newNotFoo());// 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).
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.
exportclassFooextendsMessage<Foo>{privateunused: 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'.consta0: Foo=newFooAndBar();
The text was updated successfully, but these errors were encountered:
We've looked into this, also in the context of connectrpc/connect-es#694. Unfortunately, the mitigations we investigated came with major drawbacks.
We are fixing this with the upcoming v2. Here's how v2 behaves with the example above:
import{create}from"@bufbuild/protobuf";import{FooSchema,FooAndBarSchema,NotFooSchema,typeFoo,typeNotFoo,typeFooAndBar}from"./gen/example_pb.js";consta0: Foo=create(FooAndBarSchema);// TS2322: Type FooAndBar is not assignable to type Fooconsta1: Foo=create(NotFooSchema);// TS2322: Type NotFoo is not assignable to type Fooconsta2: NotFoo=create(FooSchema);// TS2322: Type Foo is not assignable to type NotFooconsta3: NotFoo=create(FooAndBarSchema);// TS2322: Type FooAndBar is not assignable to type NotFooconsta4: FooAndBar=create(FooSchema);// TS2322: Type Foo is not assignable to type FooAndBarconsta5: FooAndBar=create(NotFooSchema);// TS2322: Type NotFoo is not assignable to type FooAndBarfunctionexample(foo: Foo){}example(create(NotFooSchema));// TS2345: Argument of type NotFoo is not assignable to parameter of type Foo
The $typeName basically gives us nominal typing. The full error is:
TS2322: Type FooAndBar is not assignable to type Foo
Type FooAndBar is not assignable to type Message<"Foo">
Types of property $typeName are incompatible.
Type "FooAndBar" is not assignable to type "Foo"
There is no compile error in
const a: ProtoA = new ProtoB()
if the fields inProtoA
are a subset of the fields inProtoB
.example.proto
example.ts
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:
The text was updated successfully, but these errors were encountered: