Skip to content

Commit

Permalink
EReturn type (#2659)
Browse files Browse the repository at this point in the history
incidental

## Description

Migrated from Agoric/agoric-sdk#9011

Define an `EReturn` type for the `Awaited<ReturnType<` pattern.

### Security Considerations

none
### Scaling Considerations

none

### Documentation Considerations

This will appear in TSdoc

### Testing Considerations

has tests

### Compatibility Considerations

none

### Upgrade Considerations

none
  • Loading branch information
turadg authored Dec 12, 2024
2 parents 2460645 + 43e4d43 commit 5df9122
Show file tree
Hide file tree
Showing 8 changed files with 48 additions and 35 deletions.
5 changes: 4 additions & 1 deletion packages/compartment-mapper/src/map-parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
* SyncModuleTransform,
* SyncModuleTransforms
* } from './types.js';
* @import {
* EReturn
* } from '@endo/eventual-send';
*/

import { syncTrampoline, asyncTrampoline } from '@endo/trampoline';
Expand Down Expand Up @@ -82,7 +85,7 @@ const makeExtensionParser = (
* @param {string} location
* @param {string} packageLocation
* @param {*} options
* @returns {Generator<ReturnType<ModuleTransform>|ReturnType<SyncModuleTransform>, ParseResult, Awaited<ReturnType<ModuleTransform>|ReturnType<SyncModuleTransform>>>}
* @returns {Generator<ReturnType<ModuleTransform>|ReturnType<SyncModuleTransform>, ParseResult, EReturn<ModuleTransform|SyncModuleTransform>>}
*/
function* getParserGenerator(
bytes,
Expand Down
6 changes: 5 additions & 1 deletion packages/daemon/test/endo.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ import { makeCryptoPowers } from '../src/daemon-node-powers.js';
import { formatId } from '../src/formula-identifier.js';
import { idFromLocator, parseLocator } from '../src/locator.js';

/**
* @import {EReturn} from '@endo/eventual-send';
*/

const cryptoPowers = makeCryptoPowers(crypto);

const { raw } = String;
Expand Down Expand Up @@ -227,7 +231,7 @@ test.beforeEach(t => {

test.afterEach.always(async t => {
await Promise.allSettled(
/** @type {Awaited<ReturnType<prepareConfig>>[]} */ (t.context).flatMap(
/** @type {EReturn<typeof prepareConfig>[]} */ (t.context).flatMap(
({ cancel, cancelled, config }) => {
cancel(Error('teardown'));
return [cancelled, stop(config)];
Expand Down
24 changes: 19 additions & 5 deletions packages/eventual-send/src/E.js
Original file line number Diff line number Diff line change
Expand Up @@ -254,8 +254,11 @@ export default makeE;
/** @typedef {ReturnType<makeE>} EProxy */

/**
* Creates a type that accepts both near and marshalled references that were
* returned from `Remotable` or `Far`, and also promises for such references.
* Declare an object that is potentially a far reference of type Primary whose
* auxilliary data has type Local. This should be used only for consumers of
* Far objects in arguments and declarations; the only creators of Far objects
* are distributed object creator components like the `Far` or `Remotable`
* functions.
*
* @template Primary The type of the primary reference.
* @template [Local=DataOnly<Primary>] The local properties of the object.
Expand All @@ -274,14 +277,24 @@ export default makeE;
* @see {@link https://github.com/microsoft/TypeScript/issues/31394}
* @template T
* @typedef {PromiseLike<T> | T} ERef
* Declare that `T` may or may not be a Promise. This should be used only for
* consumers of arguments and declarations; return values should specifically be
* `Promise<T>` or `T` itself.
*/

/**
* The awaited return type of a function.
*
* @template {(...args: any[]) => any} T
* @typedef {T extends (...args: any[]) => infer R ? Awaited<R> : never} EReturn
*/

/**
* @template {import('./types.js').Callable} T
* @typedef {(
* ReturnType<T> extends PromiseLike<infer U> // if function returns a promise
* ? T // return the function
* : (...args: Parameters<T>) => Promise<Awaited<ReturnType<T>>> // make it return a promise
* : (...args: Parameters<T>) => Promise<EReturn<T>> // make it return a promise
* )} ECallable
*/

Expand Down Expand Up @@ -399,8 +412,9 @@ export default makeE;
*/

/**
* Type for an object that must only be invoked with E. It supports a given
* interface but declares all the functions as asyncable.
* Declare a near object that must only be invoked with E, even locally. It
* supports the `T` interface but additionally permits `T`'s methods to return
* `PromiseLike`s even if `T` declares them as only synchronous.
*
* @template T
* @typedef {(
Expand Down
1 change: 1 addition & 0 deletions packages/eventual-send/src/exports.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export type {
ERef,
EProxy,
EOnly,
EReturn,
RemoteFunctions,
LocalRecord,
FilteredKeys,
Expand Down
15 changes: 14 additions & 1 deletion packages/eventual-send/src/exports.test-d.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-disable @endo/no-polymorphic-call, import/no-extraneous-dependencies, no-restricted-globals */
import { expectType } from 'tsd';
import { E } from '../test/_get-hp.js';
import type { ERef, FarRef } from './exports.js';
import type { ERef, EReturn, FarRef } from './exports.js';

// Check the legacy ERef type
const foo = async (a: ERef<{ bar(): string; baz: number }>) => {
Expand All @@ -21,6 +21,19 @@ const foo = async (a: ERef<{ bar(): string; baz: number }>) => {
a.bar();
};

// EReturn
{
const makeFoo = async () => 'foo' as const;
expectType<Promise<'foo'>>(makeFoo());
type Foo = EReturn<typeof makeFoo>;
expectType<Foo>('foo');

const fooP = Promise.resolve('foo' as const);
expectType<Promise<'foo'>>(fooP);
// @ts-expect-error takes only functions
EReturn<typeof fooP>;
}

// FarRef<T>
const foo2 = async (a: FarRef<{ bar(): string; baz: number }>) => {
const { baz } = await a;
Expand Down
1 change: 1 addition & 0 deletions packages/far/src/exports.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { FarRef, ERef, EOnly, EReturn } from '@endo/eventual-send';
2 changes: 2 additions & 0 deletions packages/far/src/exports.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Just a dummy to use exports.d.ts and satisfy runtime imports.
export {};
29 changes: 2 additions & 27 deletions packages/far/src/index.js
Original file line number Diff line number Diff line change
@@ -1,30 +1,5 @@
export { E } from '@endo/eventual-send';
export { Far, getInterfaceOf, passStyleOf } from '@endo/pass-style';

// TODO re-export from eventual-send, may require .d.ts
/**
* @template Primary
* @template [Local=import('@endo/eventual-send').DataOnly<Primary>]
* @typedef {import('@endo/eventual-send').FarRef<Primary, Local>} FarRef
* Declare an object that is potentially a far reference of type Primary whose
* auxilliary data has type Local. This should be used only for consumers of
* Far objects in arguments and declarations; the only creators of Far objects
* are distributed object creator components like the `Far` or `Remotable`
* functions.
*/

/**
* @template T
* @typedef {import('@endo/eventual-send').ERef<T>} ERef
* Declare that `T` may or may not be a Promise. This should be used only for
* consumers of arguments and declarations; return values should specifically be
* `Promise<T>` or `T` itself.
*/

/**
* @template T
* @typedef {import('@endo/eventual-send').EOnly<T>} EOnly
* Declare a near object that must only be invoked with E, even locally. It
* supports the `T` interface but additionally permits `T`'s methods to return
* `PromiseLike`s even if `T` declares them as only synchronous.
*/
// eslint-disable-next-line import/export
export * from './exports.js';

0 comments on commit 5df9122

Please sign in to comment.