Skip to content

refactor: convert intersection type aliases to interfaces for better IDE tooltips#629

Open
sp-io wants to merge 9 commits intomainfrom
refactor/interface-type-refactor
Open

refactor: convert intersection type aliases to interfaces for better IDE tooltips#629
sp-io wants to merge 9 commits intomainfrom
refactor/interface-type-refactor

Conversation

@sp-io
Copy link
Copy Markdown
Contributor

@sp-io sp-io commented Mar 13, 2026

Summary

Converts ~25 intersection type aliases (type A = B & C) to interfaces (interface A extends B, C) across @midnight-ntwrk/midnight-js-contracts to improve IDE tooltip readability.

Motivation

TypeScript handles type aliases and interface differently when displaying tooltips in IDEs:

  • type aliases using intersections are expanded inline, showing every constituent field recursively. For example, hovering over FinalizedCallTxData<C, PCK> would display a multi-line blob like:
    { public: { nextContractState: StateValue; publicTranscript: Op<AlignedValue>[]; 
    partitionedTranscript: PartitionedTranscript; } & FinalizedTxData; 
    private: { input: AlignedValue; output: AlignedValue; ... } & UnsubmittedTxData; }
    
  • interface with extends displays just the interface name: FinalizedCallTxData<C, PCK>

This makes a significant difference for developer experience when working with the SDK, especially for types with deep inheritance chains like the transaction model types.

What changed

  • Plain types (type A = { ... }) → interface A { ... } — 14 types across get-states.ts, call.ts, call-constructor.ts, tx-model.ts, find-deployed-contract.ts
  • Intersection types (type A = B & C) → interface A extends B, C — 7 types across tx-model.ts, find-deployed-contract.ts, deploy-contract.ts, unproven-call-tx.ts
  • 4 new helper interfaces in tx-model.ts for nested property intersections (e.g., where private: TypeA & TypeB needed to become a named type)

What was NOT changed

  • Conditional types (CallOptionsWithArguments, ContractConstructorOptionsWithArguments, etc.) — these use extends [] ? A : A & B which cannot be expressed as interfaces
  • Union types (FindDeployedContractOptions, CallOptions, etc.) — unions cannot be interfaces
  • Types depending on conditionals — kept as type aliases since their base types are conditional

Benefits

  • Cleaner IDE tooltips: Hover information shows the interface name instead of deeply expanded field chains
  • No breaking changes: Interfaces are structurally compatible with the original type aliases — all existing code continues to work
  • Declaration merging: Interfaces support declaration merging, giving downstream consumers more flexibility if needed

Drawbacks

  • 4 new exported helper interfaces (UnsubmittedDeployTxPrivateDataFull, FinalizedDeployTxPublicData, UnsubmittedCallTxPrivateData, FinalizedCallTxPublicData) — these are necessary to represent nested property intersections but increase the public API surface
  • Mixed type/interface style: Types that depend on conditionals must remain as type aliases, creating an inconsistency in the codebase. However, this is a TypeScript language constraint, not a design choice
  • Declaration merging risk: Unlike type aliases, interfaces can be accidentally merged if a consumer re-declares the same interface name in the same scope. This is unlikely in practice

Test plan

  • Full monorepo build passes (yarn build --force --concurrency=1)
  • Linter passes (yarn lint)
  • All tests pass (yarn test — 21/21 tasks successful)
  • Verify IDE tooltips show interface names instead of expanded types

🤖 Generated with Claude Code

sp-io and others added 9 commits March 12, 2026 17:29
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…r IDE tooltips

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…rfaces

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…er types for nested intersections

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…aces

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…FoundContract

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…e to interface

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@sp-io sp-io requested a review from a team as a code owner March 13, 2026 07:57
@sp-io sp-io added the ai-assisted Created or modified with AI assistance label Mar 13, 2026
@github-actions
Copy link
Copy Markdown
Contributor

Title Lines Statements Branches Functions
contracts Coverage: 91%
90.88% (419/461) 82.17% (166/202) 93.93% (93/99)
fetch-zk-config-provider Coverage: 94%
94.73% (18/19) 77.77% (7/9) 100% (6/6)
http-client-proof-provider Coverage: 80%
80.95% (34/42) 91.66% (11/12) 66.66% (6/9)
indexer-public-data-provider Coverage: 39%
38.61% (100/259) 25.21% (30/119) 18.01% (20/111)
level-private-state-provider Coverage: 91%
91.69% (563/614) 81% (243/300) 100% (74/74)
logger-provider Coverage: 100%
100% (15/15) 100% (0/0) 100% (8/8)
node-zk-config-provider Coverage: 100%
100% (11/11) 100% (0/0) 100% (5/5)
utils Coverage: 89%
86.79% (46/53) 80.48% (33/41) 63.63% (7/11)

@github-actions
Copy link
Copy Markdown
Contributor

Unit Test Results - MidnightJS

 20 files   58 suites   2m 38s ⏱️
408 tests 406 ✅ 2 💤 0 ❌
830 runs  826 ✅ 4 💤 0 ❌

Results for commit 5b495b0.

@MidnightCI
Copy link
Copy Markdown
Contributor

E2E Tests Results

e2e_tests_reports: Run #2966

Tests 📝 Passed ✅ Failed ❌ Skipped ⏭️ Pending ⏳ Other ❓ Flaky 🍂 Duration ⏱️
110 102 0 8 0 0 0 6m 41s

🎉 All tests passed!

Suites

102 passed, 0 failed, and 8 other

Suite Passed Failed Other Duration
✅ testkit-js/testkit-js-e2e/test/contracts.blocktime.it.test.ts
        ✅ Block Time Contract Tests 1 > blockTimeLt tests > should succeed when both device time and node time are less than future time
        ✅ Block Time Contract Tests 1 > blockTimeLt tests > should fail immediately on device when device time is already past the check time
        ⏭️ Block Time Contract Tests 1 > blockTimeLt tests > should succeed on device but fail on node when submission is delayed
        ✅ Block Time Contract Tests 1 > blockTimeLt tests > should succeed when both device time and node time are greater than past time
        ✅ Block Time Contract Tests 1 > blockTimeLt tests > should fail immediately on device when device time is less than check time
        ✅ Block Time Contract Tests 1 > blockTimeLt tests > should succeed even with submission delay when checking past time
        ✅ Block Time Contract Tests 1 > blockTimeLt tests > should succeed when both device time and node time are greater than past time
        ✅ Block Time Contract Tests 1 > blockTimeLt tests > should fail when device time is not greater than check time
        ✅ Block Time Contract Tests 1 > blockTimeLt tests > should succeed when both device time and node time are less than or equal to future time
        ✅ Block Time Contract Tests 1 > blockTimeLt tests > should fail immediately on device when device time exceeds check time
        ⏭️ Block Time Contract Tests 1 > blockTimeLt tests > should succeed on device but fail on node when submission delay causes time to exceed threshold
        ✅ Block Time Contract Tests 1 > blockTimeLt tests > should demonstrate different failure points for Lt check > Immediate past time - fails on device
        ⏭️ Block Time Contract Tests 1 > blockTimeLt tests > should demonstrate different failure points for Lt check > Near future time with delay - succeeds on device, fails on node
        ✅ Block Time Contract Tests 1 > blockTimeLt tests > should demonstrate different failure points for Lt check > Far future time - succeeds on both device and node
        ✅ Block Time Contract Tests 1 > blockTimeLt tests > should handle maximum time values
        ✅ Block Time Contract Tests 1 > blockTimeLt tests > should handle zero time value
✅ 13 ❌ 0 ⏭️ 3 2m 47s
✅ testkit-js/testkit-js-e2e/test/contracts.blocktime2.it.test.ts
        ✅ Block Time Contract Tests 2 > blockTimeLt tests > should demonstrate different failure points for Lt check > Immediate past time - fails on device
        ⏭️ Block Time Contract Tests 2 > blockTimeLt tests > should demonstrate different failure points for Lt check > Near future time with delay - succeeds on device, fails on node
        ✅ Block Time Contract Tests 2 > blockTimeLt tests > should demonstrate different failure points for Lt check > Far future time - succeeds on both device and node
        ✅ Block Time Contract Tests 2 > blockTimeLt tests > should handle maximum time values
        ✅ Block Time Contract Tests 2 > blockTimeLt tests > should handle zero time value
✅ 4 ❌ 0 ⏭️ 1 1m 11s
✅ testkit-js/testkit-js-e2e/test/contracts.it.test.ts
        ✅ Contracts API > should create unproven call and deploy transactions for contract with private state
        ✅ Contracts API > should deploy contract on the chain [@slow]
        ✅ Contracts API > should return deployed contract if it exists on specific address
        ✅ Contracts API > should return deployed contract if it exists on specific address without initialPrivateState
        ✅ Contracts API > should throw error if contract address has wrong format - length
        ✅ Contracts API > should return deployed contract if it exists on specific address with initialPrivateState and empty local private state store
        ✅ Contracts API > should return deployed contract if it exists on specific address with different initialPrivateState
        ✅ Contracts API > should wait indefinitely until contract exists on specific address [@slow]
        ✅ Contracts API > should throw for incompatible contract types that differ by circuit ids
        ✅ Contracts API > should throw for incompatible contract types with same shape but different verifier keys
        ✅ Contracts API > should return contract interface and execute circuit operations [@slow]
        ✅ Contracts API > should throw error on undefined public state at wrong address
        ✅ Contracts API > should submit a deploy transaction [@slow]
        ✅ Contracts API > should submit transaction that calls circuit in contract [@slow]
        ✅ Contracts API > should throw error if private state is undefined
        ✅ Contracts API > should throw error if public state is undefined
        ✅ Contracts API > should throw error if contract address has wrong format - not hex
        ✅ Contracts API > should return the latest observed state of a deployed contract and is independent of the chain state
        ✅ Contracts API > should wait indefinitely until state change, if stopped returns last contract state [@slow]
✅ 19 ❌ 0 ⏭️ 0 3m 23s
✅ testkit-js/testkit-js-e2e/test/contracts.scopedtx.it.test.ts
        ✅ Scoped Transaction Contract Tests > should submit scoped transaction that calls circuit in contract [@slow]
        ✅ Scoped Transaction Contract Tests > should submit scoped transaction that calls 2 different circuits in contract [@slow]
        ✅ Scoped Transaction Contract Tests > should submit scoped transaction that calls 2 circuits in contract and DOES NOT preserve execution order [@slow]
        ✅ Scoped Transaction Contract Tests > should not submit scoped transaction when one circuit call fails [@slow]
✅ 4 ❌ 0 ⏭️ 0 54.5s
✅ testkit-js/testkit-js-e2e/test/contracts.singlecontract.nostate.it.test.ts
        ✅ Contracts API > should deploy and find contracts with no private state [@slow]
        ✅ Contracts API > should create unproven call and deploy transactions for contract with no private state
        ✅ Contracts API > should submit deploy and call transactions for contracts with no private state [@slow]
✅ 3 ❌ 0 ⏭️ 0 1m 34s
✅ testkit-js/testkit-js-e2e/test/contracts.snarkupgrade.it.test.ts
        ✅ Contracts API Snark Upgrade [dedicated contract] [@slow] > should successfully remove verifier key using submitRemoveVerifierKeyTx
        ✅ Contracts API Snark Upgrade [dedicated contract] [@slow] > should successfully remove verifier key using createContractMaintenanceTxInterface
        ✅ Contracts API Snark Upgrade [dedicated contract] [@slow] > should successfully remove verifier key and disable circuit operation
        ✅ Contracts API Snark Upgrade [dedicated contract] [@slow] > should succeed on verifier key insertion retry after removal
        ✅ Contracts API Snark Upgrade [dedicated contract] [@slow] > should fail when inserting verifier key for wrong circuit after removal
✅ 5 ❌ 0 ⏭️ 0 3m 18s
✅ testkit-js/testkit-js-e2e/test/contracts.snarkupgrade.singlecontract.it.test.ts
        ✅ Contracts API Snark Upgrade [single contract] > submitReplaceAuthorityTx - successful replace authority with new key[@slow]
        ✅ Contracts API Snark Upgrade [single contract] > submitReplaceAuthorityTx - successful replace authority with same key [@slow]
        ✅ Contracts API Snark Upgrade [single contract] > submitReplaceAuthorityTx - should fail on replace contract that is not deployed to contract address
        ✅ Contracts API Snark Upgrade [single contract] > submitReplaceAuthorityTx - should fail when signing key for contract address does not exist
        ✅ Contracts API Snark Upgrade [single contract] > submitInsertVerifierKeyTx - should fail on invalid verifier key
        ✅ Contracts API Snark Upgrade [single contract] > submitInsertVerifierKeyTx - successful insert on not present circuitId [@slow]
        ✅ Contracts API Snark Upgrade [single contract] > submitInsertVerifierKeyTx - should fail on contract not present on contract address
        ✅ Contracts API Snark Upgrade [single contract] > submitInsertVerifierKeyTx - should fail on providers for different contract with different API
        ✅ Contracts API Snark Upgrade [single contract] > submitRemoveVerifierKeyTx - should fail on not present circuitId
        ✅ Contracts API Snark Upgrade [single contract] > submitRemoveVerifierKeyTx - should fail on contract not present on contract address
        ✅ Contracts API Snark Upgrade [single contract] > submitRemoveVerifierKeyTx - should fail on providers for different contract with different API
        ✅ Contracts API Snark Upgrade [single contract] > createContractMaintenanceTxInterface - replaceAuthority - successful replace authority with the new one [@slow]
        ✅ Contracts API Snark Upgrade [single contract] > createContractMaintenanceTxInterface - replaceAuthority - successful replace authority with the same one [@slow]
        ✅ Contracts API Snark Upgrade [single contract] > createContractMaintenanceTxInterface - replaceAuthority - should fail on contract not present on contract address
        ✅ Contracts API Snark Upgrade [single contract] > createContractMaintenanceTxInterface - insertVerifierKey - fail when key is still present
        ✅ Contracts API Snark Upgrade [single contract] > createContractMaintenanceTxInterface - insertVerifierKey - success when no key present [@slow]
        ✅ Contracts API Snark Upgrade [single contract] > createCircuitMaintenanceTxInterfaces - insertVerifierKey - fail when key is already present
        ✅ Contracts API Snark Upgrade [single contract] > createCircuitMaintenanceTxInterfaces - insertVerifierKey - success when no key present [@slow]
        ✅ Contracts API Snark Upgrade [single contract] > createCircuitMaintenanceTxInterfaces - removeVerifierKey - should fail on contract not present on contract address
✅ 19 ❌ 0 ⏭️ 0 3m 35s
✅ testkit-js/testkit-js-e2e/test/contracts.snarkupgrade.smoke.it.test.ts
        ✅ Contracts API Snark Upgrade [@slow][@smoke] > should update verifier keys from one contract to another [@smoke]
        ✅ Contracts API Snark Upgrade [@slow][@smoke] > should fail on operate with previous authority after replacement
✅ 2 ❌ 0 ⏭️ 0 3m 38s
✅ testkit-js/testkit-js-e2e/test/indexer-public-data-provider.observable1.it.test.ts
        ✅ Indexer API > should return the history of states starting from defined blockHash (inclusive:true, expected:1,2) [@slow]
        ✅ Indexer API > should return the history of states starting from defined blockHash (inclusive:false, expected:2) [@slow]
        ✅ Indexer API > should return the history of states starting from defined txId (inclusive:true, expected states:1,2) [@slow]
        ✅ Indexer API > should return the history of states starting from defined txId (inclusive:false, expected states:2) [@slow]
✅ 4 ❌ 0 ⏭️ 0 3m 35s
✅ testkit-js/testkit-js-e2e/test/indexer-public-data-provider.observable2.it.test.ts
        ✅ Indexer API > should return the history of states starting from defined blockHeight (inclusive:true, expected states:1,2) [@slow]
        ✅ Indexer API > should return the history of states starting from defined blockHeight (inclusive:false, expected states:2) [@slow]
        ✅ Indexer API > should return the entire history of states of the contract with the given address (config:{ type: 'all' }, expected states:0,1,2) [@slow]
        ✅ Indexer API > should return the history of states of the contract with the given address, starting with the most recent state (config:{ type: 'latest' }, expected states:1,2) [@slow]
✅ 4 ❌ 0 ⏭️ 0 3m 35s
✅ testkit-js/testkit-js-e2e/test/indexer-public-data-provider.singlecontract.it.test.ts
        ✅ Indexer API > queryDeployContractState - should return a contract state equivalent to the initial contract state produced during deployment construction
        ✅ Indexer API > queryContractState - should return the current contract state of a deployed contract
        ✅ Indexer API > queryContractState - should return the current contract state of a deployed contract at defined block height
        ✅ Indexer API > queryContractState - should return the current contract state of a deployed contract at defined block hash
        ✅ Indexer API > queryContractState - should return null on no contract at contract address
        ✅ Indexer API > queryZSwapAndContractState - should return the current ZSwap chain state and contract state of a deployed contract
        ✅ Indexer API > queryZSwapAndContractState - should return null on no contract at contract address
        ✅ Indexer API > watchForDeployTxData - should return the data of the transaction containing the deployment of the contract with the given address
        ✅ Indexer API > watchForTxData - should return the data of the transaction containing the contract call with the given transaction id
        ✅ Indexer API > watchForContractState - should immediately return the current state of a deployed contract
✅ 10 ❌ 0 ⏭️ 0 101ms
✅ testkit-js/testkit-js-e2e/test/level-private-state-provider.it.test.ts
        ✅ Level Private State Provider - Export/Import Integration > should preserve private state after database recreation [@slow]
✅ 1 ❌ 0 ⏭️ 0 56.9s
✅ testkit-js/testkit-js-e2e/test/nodejs.it.test.ts
        ✅ Ledger API - NodeJS Integration Tests > should run ESM module successfully
        ✅ Ledger API - NodeJS Integration Tests > should run CJS module with expected exit code
✅ 2 ❌ 0 ⏭️ 0 1m 36s
✅ testkit-js/testkit-js-e2e/test/proof-server.it.test.ts
        ✅ Proof server integration > should create proofs successfully for deploy and call transactions
        ✅ Proof server integration > should create proofs with transactions that has succesfull well-formedness
        ✅ Proof server integration > should execute 5 proveTx calls in parallel without errors
✅ 3 ❌ 0 ⏭️ 0 645ms
✅ testkit-js/testkit-js-e2e/test/shielded.transfer.it.test.ts
        ✅ Shielded tokens > should mint tokens
✅ 1 ❌ 0 ⏭️ 0 23.9s
✅ testkit-js/testkit-js-e2e/test/unshielded.balance.it.test.ts
        ✅ Unshielded tokens - balance > should get balance of tokens - 0 value
        ✅ Unshielded tokens - balance > should get balance of tokens - minted amount
        ✅ Unshielded tokens - balance > should get balance of tokens - greater than - false
        ✅ Unshielded tokens - balance > should get balance of tokens - greater than - true
        ✅ Unshielded tokens - balance > should get balance of tokens - less than - false
        ✅ Unshielded tokens - balance > should get balance of tokens - less than - true
✅ 6 ❌ 0 ⏭️ 0 1m 48s
✅ testkit-js/testkit-js-e2e/test/unshielded.transfer.it.test.ts
        ✅ Unshielded tokens > should mint different tokens
        ✅ Unshielded tokens > should receive tokens - invalid
        ⏭️ Unshielded tokens > should receive tokens from wallet
        ⏭️ Unshielded tokens > should send tokens to wallet
        ⏭️ Unshielded tokens > should transfer night from wallet to contract - receiveNightTokens
        ⏭️ Unshielded tokens > should transfer night to wallet - sendNightTokensToUser
✅ 2 ❌ 0 ⏭️ 4 18.0s

Github Test Reporter by CTRF 💚

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

Labels

ai-assisted Created or modified with AI assistance

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants