diff --git a/packages/pass-style/.eslintignore b/packages/pass-style/.eslintignore
new file mode 100644
index 0000000000..d76bcff161
--- /dev/null
+++ b/packages/pass-style/.eslintignore
@@ -0,0 +1,2 @@
+# typescript-eslint errors on this because it has no typecheck information, because tsc produced it for the `types.d.ts` instead
+/src/types.js
diff --git a/packages/pass-style/src/types.d.ts b/packages/pass-style/src/types.d.ts
new file mode 100644
index 0000000000..ac5efb95c9
--- /dev/null
+++ b/packages/pass-style/src/types.d.ts
@@ -0,0 +1,163 @@
+/* eslint-disable no-use-before-define */
+import { PASS_STYLE } from './passStyle-helpers.js';
+
+export type PrimitiveStyle =
+ | 'undefined'
+ | 'null'
+ | 'boolean'
+ | 'number'
+ | 'bigint'
+ | 'string'
+ | 'symbol';
+export type ContainerStyle = 'copyRecord' | 'copyArray' | 'tagged';
+export type PassStyle =
+ | PrimitiveStyle
+ | ContainerStyle
+ | 'remotable'
+ | 'error'
+ | 'promise';
+export type PassStyled = {
+ [PASS_STYLE]: S;
+};
+export type ExtractStyle
> = P[typeof PASS_STYLE];
+export type PassByCopy =
+ | import('type-fest').Primitive
+ | Error
+ | any[]
+ | CopyRecord
+ | CopyTagged;
+export type PassByRef =
+ | RemotableObject
+ | Promise
+ | Promise;
+/**
+ * A Passable is acyclic data that can be marshalled. It must be hardened to
+ * remain
+ * stable (even if some components are proxies; see PureData restriction below),
+ * and is classified by PassStyle:
+ * * Atomic primitive values have a PrimitiveStyle (PassStyle
+ * 'undefined' | 'null' | 'boolean' | 'number' | 'bigint'
+ * | 'string' | 'symbol').
+ * * Containers aggregate other Passables into
+ * * sequences as CopyArrays (PassStyle 'copyArray'), or
+ * * string-keyed dictionaries as CopyRecords (PassStyle 'copyRecord'), or
+ * * higher-level types as CopyTaggeds (PassStyle 'tagged').
+ * * PassableCaps (PassStyle 'remotable' | 'promise') expose local values to
+ * remote interaction.
+ * * As a special case to support system observability, error objects are
+ * Passable (PassStyle 'error').
+ *
+ * A Passable is essentially a pass-by-copy superstructure with a
+ * pass-by-reference
+ * exit point at the site of each PassableCap (which marshalling represents
+ * using 'slots').
+ */
+export type Passable = PassByCopy | PassByRef;
+export type PassStyleOf = {
+ (p: undefined): 'undefined';
+ (p: string): 'string';
+ (p: boolean): 'boolean';
+ (p: number): 'number';
+ (p: bigint): 'bigint';
+ (p: symbol): 'symbol';
+ (p: null): 'null';
+ (p: Promise): 'promise';
+ (p: Error): 'error';
+ (p: CopyTagged): 'tagged';
+ (p: any[]): 'copyArray';
+ (p: Iterable): 'remotable';
+ (p: Iterator): 'remotable';
+ >(p: T): ExtractStyle;
+ (p: { [key: string]: any }): 'copyRecord';
+ (p: any): PassStyle;
+};
+/**
+ * A Passable is PureData when its entire data structure is free of PassableCaps
+ * (remotables and promises) and error objects.
+ * PureData is an arbitrary composition of primitive values into CopyArray
+ * and/or
+ * CopyRecord and/or CopyTagged containers (or a single primitive value with no
+ * container), and is fully pass-by-copy.
+ *
+ * This restriction assures absence of side effects and interleaving risks *given*
+ * that none of the containers can be a Proxy instance.
+ * TODO SECURITY BUG we plan to enforce this, giving PureData the same security
+ * properties as the proposed
+ * [Records and Tuples](https://github.com/tc39/proposal-record-tuple).
+ *
+ * Given this (currently counter-factual) assumption, a PureData value cannot
+ * be used as a communications channel,
+ * and can therefore be safely shared with subgraphs that should not be able
+ * to communicate with each other.
+ * Without that assumption, such a guarantee requires a marshal-unmarshal round
+ * trip (as exists between vats) to produce data structures disconnected from
+ * any potential proxies.
+ */
+export type PureData = Passable;
+export type TaggedRecord = PassStyled & {
+ [Symbol.toStringTag]: I;
+};
+/**
+ * An object marked as remotely accessible using the `Far` or `Remotable`
+ * functions, or a local presence representing such a remote object.
+ *
+ * A more natural name would be Remotable, but that could be confused with the
+ * value of the `Remotable` export of this module (a function).
+ */
+export type RemotableObject = TaggedRecord<
+ 'remotable',
+ I
+>;
+/**
+ * The authority-bearing leaves of a Passable's pass-by-copy superstructure.
+ */
+export type PassableCap = Promise | RemotableObject;
+/**
+ * A Passable sequence of Passable values.
+ */
+export type CopyArray = T[];
+/**
+ * A Passable dictionary in which each key is a string and each value is Passable.
+ */
+export type CopyRecord = Record;
+/**
+ * A Passable "tagged record" with semantics specific to the tag identified in
+ * the `[Symbol.toStringTag]` property (such as 'copySet', 'copyBag',
+ * or 'copyMap').
+ * It must have a property with key equal to the `PASS_STYLE` export and
+ * value 'tagged'
+ * and no other properties except `[Symbol.toStringTag]` and `payload`.
+ */
+export type CopyTagged<
+ Tag extends string = string,
+ Payload extends Passable = any,
+> = TaggedRecord<'tagged', Tag> & {
+ payload: Payload;
+};
+/**
+ * This is an interface specification.
+ * For now, it is just a string, but will eventually be `PureData`. Either
+ * way, it must remain pure, so that it can be safely shared by subgraphs that
+ * are not supposed to be able to communicate.
+ */
+export type InterfaceSpec = string;
+/**
+ * Internal to a useful pattern for writing checking logic
+ * (a "checkFoo" function) that can be used to implement a predicate
+ * (an "isFoo" function) or a validator (an "assertFoo" function).
+ *
+ * * A predicate ideally only returns `true` or `false` and rarely throws.
+ * * A validator throws an informative diagnostic when the predicate
+ * would have returned `false`, and simply returns `undefined` normally
+ * when the predicate would have returned `true`.
+ * * The internal checking function that they share is parameterized by a
+ * `Checker` that determines how to proceed with a failure condition.
+ * Predicates pass in an identity function as checker. Validators
+ * pass in `assertChecker` which is a trivial wrapper around `assert`.
+ *
+ * See the various uses for good examples.
+ */
+export type Checker = (
+ cond: boolean,
+ details?: import('ses').Details | undefined,
+) => boolean;
diff --git a/packages/pass-style/src/types.js b/packages/pass-style/src/types.js
index e77c3dd67d..407ac0b20e 100644
--- a/packages/pass-style/src/types.js
+++ b/packages/pass-style/src/types.js
@@ -1,189 +1,5 @@
-/* eslint-disable no-unused-vars */
+/** @file Empty twin for .d.ts */
+/* eslint-disable */
import { PASS_STYLE } from './passStyle-helpers.js';
export {};
-
-/**
- * @typedef { 'undefined' | 'null' |
- * 'boolean' | 'number' | 'bigint' | 'string' | 'symbol'
- * } PrimitiveStyle
- */
-
-/** @typedef {'copyRecord' | 'copyArray' | 'tagged'} ContainerStyle */
-
-/**
- * @typedef { PrimitiveStyle |
- * ContainerStyle |
- * 'remotable' |
- * 'error' | 'promise'
- * } PassStyle
- */
-
-/**
- * @template {string} S style
- * @typedef {{ [PASS_STYLE]: S }} PassStyled
- */
-
-/**
- * @template {PassStyled} P
- * @typedef {P[typeof PASS_STYLE]} ExtractStyle
- */
-
-/** @typedef {import('type-fest').Primitive | Error | CopyArray | CopyRecord | CopyTagged } PassByCopy */
-/** @typedef {RemotableObject | Promise | Promise } PassByRef */
-
-/**
- * @typedef {PassByCopy | PassByRef} Passable
- *
- * A Passable is acyclic data that can be marshalled. It must be hardened to
- * remain
- * stable (even if some components are proxies; see PureData restriction below),
- * and is classified by PassStyle:
- * * Atomic primitive values have a PrimitiveStyle (PassStyle
- * 'undefined' | 'null' | 'boolean' | 'number' | 'bigint'
- * | 'string' | 'symbol').
- * * Containers aggregate other Passables into
- * * sequences as CopyArrays (PassStyle 'copyArray'), or
- * * string-keyed dictionaries as CopyRecords (PassStyle 'copyRecord'), or
- * * higher-level types as CopyTaggeds (PassStyle 'tagged').
- * * PassableCaps (PassStyle 'remotable' | 'promise') expose local values to
- * remote interaction.
- * * As a special case to support system observability, error objects are
- * Passable (PassStyle 'error').
- *
- * A Passable is essentially a pass-by-copy superstructure with a
- * pass-by-reference
- * exit point at the site of each PassableCap (which marshalling represents
- * using 'slots').
- */
-
-// Cases match in sequence. The final case 'remotable' is for a Passable that isn't one of the others.
-/**
- * @typedef {{
- * (p: undefined): 'undefined';
- * (p: string): 'string';
- * (p: boolean): 'boolean';
- * (p: number): 'number';
- * (p: bigint): 'bigint';
- * (p: symbol): 'symbol';
- * (p: null): 'null';
- * (p: Promise): 'promise';
- * (p: Error): 'error';
- * (p: CopyTagged): 'tagged';
- * (p: Array): 'copyArray';
- * (p: Iterable): 'remotable';
- * (p: Iterator): 'remotable';
- * >(p: T): ExtractStyle
- * (p: {[key: string]: any}): 'copyRecord';
- * (p: RemotableObject): 'remotable';
- * (p: any): PassStyle;
- * }} PassStyleOf
- */
-
-/**
- * @typedef {Passable} PureData
- *
- * A Passable is PureData when its entire data structure is free of PassableCaps
- * (remotables and promises) and error objects.
- * PureData is an arbitrary composition of primitive values into CopyArray
- * and/or
- * CopyRecord and/or CopyTagged containers (or a single primitive value with no
- * container), and is fully pass-by-copy.
- *
- * This restriction assures absence of side effects and interleaving risks *given*
- * that none of the containers can be a Proxy instance.
- * TODO SECURITY BUG we plan to enforce this, giving PureData the same security
- * properties as the proposed
- * [Records and Tuples](https://github.com/tc39/proposal-record-tuple).
- *
- * Given this (currently counter-factual) assumption, a PureData value cannot
- * be used as a communications channel,
- * and can therefore be safely shared with subgraphs that should not be able
- * to communicate with each other.
- * Without that assumption, such a guarantee requires a marshal-unmarshal round
- * trip (as exists between vats) to produce data structures disconnected from
- * any potential proxies.
- */
-
-/**
- * @template {string} S pass style
- * @template {InterfaceSpec} I interface tag
- * @typedef {PassStyled & {[Symbol.toStringTag]: I}} TaggedRecord
- */
-
-/**
- * @template {InterfaceSpec} [I=string]
- * @typedef {TaggedRecord<'remotable', I>} RemotableObject
- *
- * An object marked as remotely accessible using the `Far` or `Remotable`
- * functions, or a local presence representing such a remote object.
- *
- * A more natural name would be Remotable, but that could be confused with the
- * value of the `Remotable` export of this module (a function).
- */
-
-/**
- * @typedef {Promise | RemotableObject} PassableCap
- *
- * The authority-bearing leaves of a Passable's pass-by-copy superstructure.
- */
-
-// TODO a better default type. Ideally it's Passable, but that causes a circular definition.
-/**
- * @template {Passable} [T=object]
- * @typedef {T[]} CopyArray
- *
- * A Passable sequence of Passable values.
- */
-
-// TODO a better default type. Ideally it's Passable, but that causes a circular definition.
-/**
- * @template {Passable} [T=object]
- * @typedef {Record} CopyRecord
- *
- * A Passable dictionary in which each key is a string and each value is Passable.
- */
-
-/**
- * @template {InterfaceSpec} [Tag=string]
- * @template {Passable} [Payload=any]
- * @typedef {TaggedRecord<'tagged', Tag> & {
- * payload: Payload,
- * }} CopyTagged
- *
- * A Passable "tagged record" with semantics specific to the tag identified in
- * the `[Symbol.toStringTag]` property (such as 'copySet', 'copyBag',
- * or 'copyMap').
- * It must have a property with key equal to the `PASS_STYLE` export and
- * value 'tagged'
- * and no other properties except `[Symbol.toStringTag]` and `payload`.
- */
-
-/**
- * @typedef {string} InterfaceSpec
- * This is an interface specification.
- * For now, it is just a string, but will eventually be `PureData`. Either
- * way, it must remain pure, so that it can be safely shared by subgraphs that
- * are not supposed to be able to communicate.
- */
-
-/**
- * @callback Checker
- * Internal to a useful pattern for writing checking logic
- * (a "checkFoo" function) that can be used to implement a predicate
- * (an "isFoo" function) or a validator (an "assertFoo" function).
- *
- * * A predicate ideally only returns `true` or `false` and rarely throws.
- * * A validator throws an informative diagnostic when the predicate
- * would have returned `false`, and simply returns `undefined` normally
- * when the predicate would have returned `true`.
- * * The internal checking function that they share is parameterized by a
- * `Checker` that determines how to proceed with a failure condition.
- * Predicates pass in an identity function as checker. Validators
- * pass in `assertChecker` which is a trivial wrapper around `assert`.
- *
- * See the various uses for good examples.
- * @param {boolean} cond
- * @param {import('ses').Details} [details]
- * @returns {boolean}
- */