endojs / endo

Endo is a distributed secure JavaScript sandbox, based on SES
Apache License 2.0
837 stars 72 forks source link

patterns: Constructing a pattern should also create a static type #2392

Open gibson042 opened 4 months ago

gibson042 commented 4 months ago

What is the Problem Being Solved?

Independently constructing runtime patterns with M matcher methods and defining static types with @typedef is cumbersome and error-prone, leading us to implement manual validation even when M would be useful (cf. https://github.com/Agoric/agoric-sdk/pull/9169#discussion_r1690588997). It should instead be possible to extract static types from patterns, e.g.

import { mustMatch } from '@endo/patterns';

const BundleShape = M.or(…);

/**
 * @param {TypeFromPattern<typeof BundleShape>} bundle
 */
const evaluateBundle = bundle => {
  mustMatch(bundle, BundleShape);
  const { moduleFormat } = bundle;
  …
};

evaluateBundle({}); // static error

Description of the Design

Annotate Matcher functions to return annotated values, and define a utility type for reading such annotations into types.

Security Considerations

None AFAIK

Scaling Considerations

None AFAIK

Test Plan

We should take examples from existing endo and agoric-sdk code.

Compatibility Considerations

None AFAIK

Upgrade Considerations

Nothing out of the ordinary, just the usual caveat that functionality is not incorporated into mainnet vats until they are upgraded.

gibson042 commented 4 months ago

A successful experiment that leverages const annotation for raw primitives: TypeScript Playground

I'm near the current limits of my knowledge, but this looks very promising as a step beyond even https://github.com/Agoric/agoric-sdk/blob/master/packages/internal/src/types.d.ts#L75-L96 .

screen

gibson042 commented 4 months ago

And a version with recursive types (which must be actual TypeScript AFAIK) for recognizing e.g. { version: /** @type {const} */ (1), contents: M.string() } as a Pattern without the need for a wrapping call: TypeScript Playground