From 609a3242bef53432b5ec6378ef576bf6a876efce Mon Sep 17 00:00:00 2001 From: Timo Stamm Date: Wed, 18 Sep 2024 12:47:32 +0200 Subject: [PATCH] Fix assignability of wrong message type in create --- .../protobuf-test/extra/ts-types-proto2.proto | 26 +++++++ packages/protobuf-test/src/create.test.ts | 7 ++ .../src/gen/js/extra/ts-types-proto2_pb.d.ts | 68 ++++++++++++++++++ .../src/gen/js/extra/ts-types-proto2_pb.js | 40 +++++++++++ .../src/gen/ts/extra/ts-types-proto2_pb.ts | 72 +++++++++++++++++++ packages/protobuf/src/types.ts | 10 +-- 6 files changed, 218 insertions(+), 5 deletions(-) create mode 100644 packages/protobuf-test/extra/ts-types-proto2.proto create mode 100644 packages/protobuf-test/src/gen/js/extra/ts-types-proto2_pb.d.ts create mode 100644 packages/protobuf-test/src/gen/js/extra/ts-types-proto2_pb.js create mode 100644 packages/protobuf-test/src/gen/ts/extra/ts-types-proto2_pb.ts diff --git a/packages/protobuf-test/extra/ts-types-proto2.proto b/packages/protobuf-test/extra/ts-types-proto2.proto new file mode 100644 index 000000000..bb002b2c6 --- /dev/null +++ b/packages/protobuf-test/extra/ts-types-proto2.proto @@ -0,0 +1,26 @@ +// Copyright 2021-2024 Buf Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto2"; +package spec; + +message TsTypeA { + optional string str = 1; + optional TsTypeA child = 2; +} + +message TsTypeB { + optional string str = 1; + optional TsTypeB child = 2; +} diff --git a/packages/protobuf-test/src/create.test.ts b/packages/protobuf-test/src/create.test.ts index 2d9a29e31..567b08952 100644 --- a/packages/protobuf-test/src/create.test.ts +++ b/packages/protobuf-test/src/create.test.ts @@ -27,6 +27,7 @@ import * as proto3_ts from "./gen/ts/extra/proto3_pb.js"; import * as proto2_ts from "./gen/ts/extra/proto2_pb.js"; import * as edition2023_ts from "./gen/ts/extra/edition2023_pb.js"; import * as test_messages_proto3_editions_ts from "./gen/ts/editions/golden/test_messages_proto3_editions_pb.js"; +import * as ts_types from "./gen/ts/extra/ts-types-proto2_pb.js"; import { fillProto3Message, fillProto3MessageNames } from "./helpers-proto3.js"; import { fillEdition2023Message, @@ -549,6 +550,12 @@ describe("create()", () => { const notAUser = create(proto3_ts.Proto3MessageSchema, user); expect(notAUser).toBeDefined(); }); + test("rejects foreign typed message with assignable properties as a type error", () => { + const a = create(ts_types.TsTypeASchema); + // @ts-expect-error TS2345: Argument of type TsTypeA is not assignable to parameter of type MessageInit | undefined + const b = create(ts_types.TsTypeBSchema, a); + expect(b).toBeDefined(); + }); test("rejects extra properties in the object literal as a type error", () => { const msg = create(proto3_ts.Proto3MessageSchema, { // @ts-expect-error TS2353 diff --git a/packages/protobuf-test/src/gen/js/extra/ts-types-proto2_pb.d.ts b/packages/protobuf-test/src/gen/js/extra/ts-types-proto2_pb.d.ts new file mode 100644 index 000000000..1872b97be --- /dev/null +++ b/packages/protobuf-test/src/gen/js/extra/ts-types-proto2_pb.d.ts @@ -0,0 +1,68 @@ +// Copyright 2021-2024 Buf Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// @generated by protoc-gen-es v2.0.0 with parameter "target=js+dts,import_extension=js" +// @generated from file extra/ts-types-proto2.proto (package spec, syntax proto2) +/* eslint-disable */ + +import type { GenFile, GenMessage } from "@bufbuild/protobuf/codegenv1"; +import type { Message } from "@bufbuild/protobuf"; + +/** + * Describes the file extra/ts-types-proto2.proto. + */ +export declare const file_extra_ts_types_proto2: GenFile; + +/** + * @generated from message spec.TsTypeA + */ +export declare type TsTypeA = Message<"spec.TsTypeA"> & { + /** + * @generated from field: optional string str = 1; + */ + str: string; + + /** + * @generated from field: optional spec.TsTypeA child = 2; + */ + child?: TsTypeA; +}; + +/** + * Describes the message spec.TsTypeA. + * Use `create(TsTypeASchema)` to create a new message. + */ +export declare const TsTypeASchema: GenMessage; + +/** + * @generated from message spec.TsTypeB + */ +export declare type TsTypeB = Message<"spec.TsTypeB"> & { + /** + * @generated from field: optional string str = 1; + */ + str: string; + + /** + * @generated from field: optional spec.TsTypeB child = 2; + */ + child?: TsTypeB; +}; + +/** + * Describes the message spec.TsTypeB. + * Use `create(TsTypeBSchema)` to create a new message. + */ +export declare const TsTypeBSchema: GenMessage; + diff --git a/packages/protobuf-test/src/gen/js/extra/ts-types-proto2_pb.js b/packages/protobuf-test/src/gen/js/extra/ts-types-proto2_pb.js new file mode 100644 index 000000000..14af1849c --- /dev/null +++ b/packages/protobuf-test/src/gen/js/extra/ts-types-proto2_pb.js @@ -0,0 +1,40 @@ +// Copyright 2021-2024 Buf Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// @generated by protoc-gen-es v2.0.0 with parameter "target=js+dts,import_extension=js" +// @generated from file extra/ts-types-proto2.proto (package spec, syntax proto2) +/* eslint-disable */ + +import { fileDesc, messageDesc } from "@bufbuild/protobuf/codegenv1"; + +/** + * Describes the file extra/ts-types-proto2.proto. + */ +export const file_extra_ts_types_proto2 = /*@__PURE__*/ + fileDesc("ChtleHRyYS90cy10eXBlcy1wcm90bzIucHJvdG8SBHNwZWMiNAoHVHNUeXBlQRILCgNzdHIYASABKAkSHAoFY2hpbGQYAiABKAsyDS5zcGVjLlRzVHlwZUEiNAoHVHNUeXBlQhILCgNzdHIYASABKAkSHAoFY2hpbGQYAiABKAsyDS5zcGVjLlRzVHlwZUI"); + +/** + * Describes the message spec.TsTypeA. + * Use `create(TsTypeASchema)` to create a new message. + */ +export const TsTypeASchema = /*@__PURE__*/ + messageDesc(file_extra_ts_types_proto2, 0); + +/** + * Describes the message spec.TsTypeB. + * Use `create(TsTypeBSchema)` to create a new message. + */ +export const TsTypeBSchema = /*@__PURE__*/ + messageDesc(file_extra_ts_types_proto2, 1); + diff --git a/packages/protobuf-test/src/gen/ts/extra/ts-types-proto2_pb.ts b/packages/protobuf-test/src/gen/ts/extra/ts-types-proto2_pb.ts new file mode 100644 index 000000000..7ec6090e3 --- /dev/null +++ b/packages/protobuf-test/src/gen/ts/extra/ts-types-proto2_pb.ts @@ -0,0 +1,72 @@ +// Copyright 2021-2024 Buf Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// @generated by protoc-gen-es v2.0.0 with parameter "target=ts,import_extension=js" +// @generated from file extra/ts-types-proto2.proto (package spec, syntax proto2) +/* eslint-disable */ + +import type { GenFile, GenMessage } from "@bufbuild/protobuf/codegenv1"; +import { fileDesc, messageDesc } from "@bufbuild/protobuf/codegenv1"; +import type { Message } from "@bufbuild/protobuf"; + +/** + * Describes the file extra/ts-types-proto2.proto. + */ +export const file_extra_ts_types_proto2: GenFile = /*@__PURE__*/ + fileDesc("ChtleHRyYS90cy10eXBlcy1wcm90bzIucHJvdG8SBHNwZWMiNAoHVHNUeXBlQRILCgNzdHIYASABKAkSHAoFY2hpbGQYAiABKAsyDS5zcGVjLlRzVHlwZUEiNAoHVHNUeXBlQhILCgNzdHIYASABKAkSHAoFY2hpbGQYAiABKAsyDS5zcGVjLlRzVHlwZUI"); + +/** + * @generated from message spec.TsTypeA + */ +export type TsTypeA = Message<"spec.TsTypeA"> & { + /** + * @generated from field: optional string str = 1; + */ + str: string; + + /** + * @generated from field: optional spec.TsTypeA child = 2; + */ + child?: TsTypeA; +}; + +/** + * Describes the message spec.TsTypeA. + * Use `create(TsTypeASchema)` to create a new message. + */ +export const TsTypeASchema: GenMessage = /*@__PURE__*/ + messageDesc(file_extra_ts_types_proto2, 0); + +/** + * @generated from message spec.TsTypeB + */ +export type TsTypeB = Message<"spec.TsTypeB"> & { + /** + * @generated from field: optional string str = 1; + */ + str: string; + + /** + * @generated from field: optional spec.TsTypeB child = 2; + */ + child?: TsTypeB; +}; + +/** + * Describes the message spec.TsTypeB. + * Use `create(TsTypeBSchema)` to create a new message. + */ +export const TsTypeBSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_extra_ts_types_proto2, 1); + diff --git a/packages/protobuf/src/types.ts b/packages/protobuf/src/types.ts index 80389fcb3..0a69d8805 100644 --- a/packages/protobuf/src/types.ts +++ b/packages/protobuf/src/types.ts @@ -50,7 +50,7 @@ export type MessageJsonType = */ export type MessageInitShape = Desc extends GenMessage - ? RuntimeShape | MessageInit + ? MessageInit : Record; /** @@ -93,10 +93,10 @@ export type UnknownField = { * The init type for a message, which makes all fields optional. * The init type is accepted by the function create(). */ -type MessageInit = { - [P in keyof T as P extends "$typeName" | "$unknown" ? never : P]?: FieldInit< - T[P] - >; +type MessageInit = T | { + [P in keyof T as P extends "$unknown" ? never : P]?: P extends "$typeName" + ? never + : FieldInit; }; // prettier-ignore