Skip to content

Generated, compiled Codec.typeUrl is just TS type string #795

@michaelfig

Description

@michaelfig

Situation

Here's a difference from what Telescope generates today versus what I want from it:

diff --git a/src/codegen/circle/cctp/v1/attester.ts b/src/codegen/circle/cctp/v1/attester.ts
index 24d3c1b1dd..c5e728ae6a 100644
--- a/src/codegen/circle/cctp/v1/attester.ts
+++ b/src/codegen/circle/cctp/v1/attester.ts
@@ -26,7 +26,7 @@ function createBaseAttester(): Attester {
   };
 }
 export const Attester = {
-  typeUrl: '/circle.cctp.v1.Attester',
+  typeUrl: '/circle.cctp.v1.Attester' as const,
   encode(
     message: Attester,
     writer: BinaryWriter = BinaryWriter.create(),

Without the as const, the Typescript compiler output is (today vs. what I want):

--- a/dist/codegen/circle/cctp/v1/attester.d.ts.orig      2025-07-11 20:52:11
+++ b/dist/codegen/circle/cctp/v1/attester.d.ts   2025-07-11 18:56:39
@@ -19,7 +19,7 @@
     attester: string;
 }
 export declare const Attester: {
-    typeUrl: string;
+    typeUrl: "/circle.cctp.v1.Attester";
     encode(message: Attester, writer?: BinaryWriter): BinaryWriter;
     decode(input: BinaryReader | Uint8Array, length?: number): Attester;
     fromJSON(object: any): Attester;

Impact

Because of that missing as const, an importer of the compiled files cannot use the narrow typeUrl constants because they're all just string. That's bad because it forces the user to rely on creating type registries rather than just grabbing Codec['typeUrl'].

Solution

Turns out this is really easy to solve:

--- a/packages/ast/src/encoding/proto/props/index.ts
+++ b/packages/ast/src/encoding/proto/props/index.ts
@@ -3,6 +3,9 @@ import { ProtoParseContext } from '../../context';
 import { ProtoType } from '@cosmology/types';
 import { getAminoTypeName, getTypeUrl } from '../../amino';
 
+const asConst = (expr: t.Expression) =>
+  t.tSAsExpression(expr, t.tsTypeReference(t.identifier('const')));
+
 export const createTypeUrlProperty = (
     context: ProtoParseContext,
     proto: ProtoType
@@ -11,7 +14,7 @@ export const createTypeUrlProperty = (
     if (!typeUrl) return;
     return t.objectProperty(
         t.identifier('typeUrl'),
-        t.stringLiteral(typeUrl)
+        asConst(t.stringLiteral(typeUrl))
     )
 };
 
@@ -23,6 +26,6 @@ export const createAminoTypeProperty = (
     if (!str || str.startsWith('/')) return;
     return t.objectProperty(
         t.identifier('aminoType'),
-        t.stringLiteral(str)
+        asConst(t.stringLiteral(str))
     )
 };

With this patch, I don't need anything else from you, but I thought I'd share it in case you wanted to adopt it upstream (with tests, of course).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions