Accepted
When implementing proto generation for TypeScript (ADR-006), we found ts-proto by default generates:
Our TypeScript code communicates via WebSocket with JSON, not gRPC with protobuf binary format.
Generate only TypeScript interfaces from proto files, skipping all serialization and gRPC code.
${pkgs.protobuf}/bin/protoc \
--plugin=protoc-gen-ts_proto=... \
--ts_proto_opt=esModuleInterop=true \
--ts_proto_out=web/ts/generated/proto \
plugin/grpc/protocol/atsstore.proto
Result: Includes serialization, gRPC clients, requires @bufbuild/protobuf
We only use the interface definitions. All serialization and gRPC code is unused.
${pkgs.protobuf}/bin/protoc \
--plugin=protoc-gen-ts_proto=... \
--ts_proto_opt=esModuleInterop=true \
--ts_proto_opt=outputEncodeMethods=false \
--ts_proto_opt=outputJsonMethods=false \
--ts_proto_opt=outputClientImpl=false \
--ts_proto_opt=outputServices=false \
--ts_proto_opt=onlyTypes=true \
--ts_proto_out=web/ts/generated/proto \
plugin/grpc/protocol/atsstore.proto
Result: 97 lines, no dependencies needed
// plugin/grpc/protocol/atsstore.proto
message Attestation {
string id = 1;
repeated string subjects = 2;
repeated string predicates = 3;
// ...
}
// web/ts/generated/proto/plugin/grpc/protocol/atsstore.ts
export interface Attestation {
id: string;
subjects: string[];
predicates: string[];
// ... just the fields
}
// web/ts/components/glyph/ax-glyph.ts
import type { Attestation } from '../../generated/proto/plugin/grpc/protocol/atsstore';
// Before: const matchedAttestations: any[] = [];
const matchedAttestations: Attestation[] = []; // Type safety!
function renderAttestation(attestation: Attestation): HTMLElement {
// Full IDE autocomplete and type checking
}
any types in ax-glyph.tsThis is a proven pattern. For any new proto type:
any with typed interfacebun run typecheck to verifyInitially discovered that proto field names didn't match Go's JSON output:
attributes_json, Go sends "attributes"Solution:
attributes_json → attributes)snakeToCamel=false to preserve snake_case in TypeScriptWhile field names now match, type representations still differ:
number (Unix seconds), Go sends ISO stringas AttestationThis pattern works. When implementing proto generation for other languages, question what you actually need. The best generated code is often the least generated code.