Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: option to declare schema as const (#1096)
This PR adds a new option that allows us to get additional type information for the `protoMetadata` export when using `outputSchema=true`. ## Background Using the `outputSchema=true` option, ts-proto outputs a `protoMetadata` export for all proto files. This metadata object can be useful for rudimentary reflection and required if we want to access value options. Unfortunately there is no compile time type safety for these values, because the export is declared as `ProtoMetadata`, losing a lot of useful type information. ## Proposed Solution When setting the option `outputSchemaAsConst=true`, do the following: Instead of doing `export const protoMetadata: ProtoMetadata = { ... }`, export it as `export const protoMetadata = { ... } as const satisfies ProtoMetadata`. This retains the full value of `protoMetadata` on the type level. This additional type information can then be used to write type safe reflection methods, like for accessing the values of value options declared in proto files (see the included tests for some basic examples). In order to provide type safety for the `fileDescriptor` field, I had to remove the call to `FileDescriptorProto.fromPartial(...)`. As far as I can tell this call doesn't do much in practice, because the data passed to it at code generation time was already passed through `FileDescriptorProto.fromPartial(fileDesc)` and I _think_ this results in the exact same value, making the `fromPartial` call in the generated code basically a no-op. You might want to double-check this before merging because this change isn't hidden behind the `outputSchemaAsConst` option. ## Considerations ### `satisfies` operator The `satisfies ProtoMetadata` part of the declaration isn't strictly necessary as the exported value should match the `ProtoMetadata` interface anyway. However, it can act as a hint to developers that the export conforms to the `ProtoMetadata` type instead of being completely independent. It also acts as a kind of sanity check when type checking, making sure the generated type matches our expectations. The `satisfies` operator is only supported since TypeScript 4.9, so code generated using this option will not work on older TS versions. ### type complexity When declaring `protoMetadata` as const, the type definition blows up _a lot_, because the whole value is now also encoded on the type level. This allows for advanced use cases (like typesafe reflecton), but could potentially slow down the compiler when dealing with large schemas. It also increases type declaration file sizes when the typescript files when the resulting `.ts` files are compiled to `.js` and `.d.ts` files.
- Loading branch information