Skip to content

Commit

Permalink
test(types): PromiseToVow behavior
Browse files Browse the repository at this point in the history
  • Loading branch information
0xpatrickdev committed Jun 28, 2024
1 parent a22f7f7 commit 2dcc26f
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 6 deletions.
2 changes: 1 addition & 1 deletion packages/orchestration/src/exos/local-chain-facade.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ const prepareLocalChainFacadeKit = (
makeAccount() {
const lcaP = E(localchain).makeAccount();
// TODO #9449 fix types
// @ts-expect-error 'Vow<Guarded<{...}>> is not assignable to type 'Vow<never>'
// @ts-expect-error Type 'Vow<Voidless>' is not assignable to type 'Vow<OrchestrationAccountI>'.
return watch(
// TODO #9449 fix types
// @ts-expect-error Property 'getAddress' does not exist on type 'EMethods<Required<Guarded<{ getAddress()...
Expand Down
2 changes: 1 addition & 1 deletion packages/orchestration/src/exos/remote-chain-facade.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ const prepareRemoteChainFacadeKit = (
/** @returns {Vow<PromiseToVow<OrchestrationAccount<ChainInfo>>>} */
makeAccount() {
// TODO #9449 fix types
// @ts-expect-error 'Vow<Guarded<{...}>> is not assignable to type 'Vow<never>' #9449
// @ts-expect-error Type 'Vow<Voidless>' is not assignable to type 'Vow<OrchestrationAccountI>'
return asVow(() => {
const { remoteChainInfo, connectionInfo } = this.state;
const stakingDenom = remoteChainInfo.stakingTokens?.[0]?.denom;
Expand Down
17 changes: 14 additions & 3 deletions packages/orchestration/src/internal.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
import type { Vow } from '@agoric/vow';

export type PromiseToVow<T> = T extends (...args: infer A) => Promise<infer R>
? (...args: A) => Vow<R>
: never;
/**
* Converts a function type that returns a Promise to a function type that
* returns a Vow. If the input is not a function returning a Promise, it
* preserves the original type.
*
* @template T - The type to transform
*/
export type PromiseToVow<T> = T extends (
...args: infer Args
) => Promise<infer R>
? (...args: Args) => Vow<R>
: T extends (...args: infer Args) => infer R
? (...args: Args) => R
: T;

export type VowifyAll<T> = {
[K in keyof T]: PromiseToVow<T[K]>;
Expand Down
57 changes: 56 additions & 1 deletion packages/orchestration/test/types.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@ import { expectNotType, expectType } from 'tsd';
import { typedJson } from '@agoric/cosmic-proto';
import type { MsgDelegateResponse } from '@agoric/cosmic-proto/cosmos/staking/v1beta1/tx.js';
import type { QueryAllBalancesResponse } from '@agoric/cosmic-proto/cosmos/bank/v1beta1/query.js';
import type { Vow } from '@agoric/vow';
import type {
ChainAddress,
CosmosValidatorAddress,
StakingAccountActions,
OrchestrationAccount,
} from '../src/types.js';
import type { LocalOrchestrationAccountKit } from '../src/exos/local-orchestration-account.js';
import { prepareCosmosOrchestrationAccount } from '../src/exos/cosmos-orchestration-account.js';
import type { VowifyAll } from '../src/internal.js';
import type { PromiseToVow, VowifyAll } from '../src/internal.js';

const anyVal = null as any;

Expand Down Expand Up @@ -69,3 +71,56 @@ expectNotType<CosmosValidatorAddress>(chainAddr);
anyVal,
) satisfies VowifyAll<StakingAccountActions>;
}

// PromiseToVow
{
type PromiseFn = () => Promise<number>;
type SyncFn = () => number;

type VowFn = PromiseToVow<PromiseFn>;
type StillSyncFn = PromiseToVow<SyncFn>;

// Use type assertion instead of casting
const vowFn: VowFn = (() => ({}) as Vow<number>) as VowFn;
expectType<() => Vow<number>>(vowFn);

const syncFn: StillSyncFn = (() => 42) as StillSyncFn;
expectType<() => number>(syncFn);

// Negative test
expectNotType<() => Promise<number>>(vowFn);
}

// PromiseToVow with TransferSteps
{
type TransferStepsVow = PromiseToVow<
OrchestrationAccount<any>['transferSteps']
>;

const transferStepsVow: TransferStepsVow = (...args: any[]): Vow<any> =>
({}) as any;
expectType<(...args: any[]) => Vow<any>>(transferStepsVow);
}

// VowifyAll
{
type PromiseObject = {
foo: () => Promise<number>;
bar: (x: string) => Promise<boolean>;
bizz: () => Record<string, number>;
};

type VowObject = VowifyAll<PromiseObject>;

const vowObject: VowObject = {
foo: () => ({}) as Vow<number>,
bar: (x: string) => ({}) as Vow<boolean>,
bizz: () => ({ foo: 1 }),
};

expectType<{
foo: () => Vow<number>;
bar: (x: string) => Vow<boolean>;
bizz: () => Record<string, number>;
}>(vowObject);
}

0 comments on commit 2dcc26f

Please sign in to comment.