Skip to content

feat: typed client poc - #1860

Open
hugo-stacks wants to merge 1 commit into
mainfrom
feat/typed-client-poc
Open

feat: typed client poc#1860
hugo-stacks wants to merge 1 commit into
mainfrom
feat/typed-client-poc

Conversation

@hugo-stacks

@hugo-stacks hugo-stacks commented May 15, 2026

Copy link
Copy Markdown
Contributor

poc

Explore 2 approaches for a typed contract client.
Details here: stx-labs/clarinet#2364

The "generated/" directory comes from a new clarinet typegen command, that also explore the two approaches (pr here stx-labs/clarinet#2393)

goals

The code itself doesn't really matter here (we won't fully implement and review the two approaches). But the goal is two pick the approach we want to go with.

You can see the new lib in actions in packages/stck/tests/playground/index.ts.

The important bits are

// approach A
counterA.makeUnsignedContractCall()
counterA.fetchCallReadOnlyFunction()

// approachB
counterB.makeUnsignedContractCall()
counterB.fetchCallReadOnlyFunction()

The goal really is to play with these parts of the code, hover the types and introduce errors (eg: extra function arg, string instead of number, etc) to see how TS handles the type errors.

The most visible difference is on hovering the functions makeUnsignedContractCall.

counterA.makeUnsignedContractCall('add', [5]);
//              ^ (method) makeUnsignedContractCall<"add">(functionName: "add", args: [number | bigint | UIntCV], opts?: PerCallOptions): Promise<StacksTransactionWire>
counterB.makeUnsignedContractCall('add', [5]);
//.             ^ (method) ContractClientB<{ readonly functions: readonly [{ readonly name: "add"; readonly access: "public"; readonly args: readonly [{ readonly name: "n"; readonly type: "uint128"; }]; readonly outputs: { readonly type: { readonly response: { ...; }; }; }; }, { ...; }, { ...; }, { ...; }, { ...; }]; ... 5 more ...; readonly clarity_version: "Clarity4"; } & { ...; }>.makeUnsignedContractCall<"add">(functionName: "add", args: [number | bigint | UIntCV], opts?: PerCallOptions): Promise<StacksTransactionWire>

Approach A, because it has types aliases, really shows an superiority in terms of DX here


You may find some dead code or older decision patterns. I explored multiple paths (eg: kebab-case to camelCase function name to do counter.getCount([]) instead of counter.fetchCallReadOnlyFunction('get-count', []).
I think both approach are still on the table here, but none of these design decisions are set in stone at this point. Implementation details

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant