Chapter 2
Proxied<T>: tracing property access
A Ref<T> carries a typed JSONPath — but writing those paths by hand is the thing we are trying to avoid. createProxy<T>() is the answer.
It returns a Proxied<T>: a Proxy where every property access records the property name as a path segment and returns a new proxy for that property's type. Ordinary TypeScript property access is silently traced into a JSONPath string.
type type State = {
bucket: string;
mediaInfo: {
width: number;
height: number;
};
}
State = {
bucket: stringbucket: string;
mediaInfo: {
width: number;
height: number;
}
mediaInfo: { width: numberwidth: number; height: numberheight: number };
};
const const ctx: Proxied<State>ctx = createProxy<State>(path?: string[]): Proxied<State>Creates a typed Proxy that records property access as JSONPath segments.
Every property access on the returned proxy returns a new proxy with
the property name appended to the path. Numeric keys (e.g. `[0]`) are
recorded as array index segments.createProxy<type State = {
bucket: string;
mediaInfo: {
width: number;
height: number;
};
}
State>();
function pathOf(ref: Ref<unknown>): stringExtracts the JSONPath string from a Ref.
Converts the internal path segments into a dot-separated JSONPath string,
with array indices attached directly (no dot before brackets).pathOf(const ctx: Proxied<State>ctx); // '$'
function pathOf(ref: Ref<unknown>): stringExtracts the JSONPath string from a Ref.
Converts the internal path segments into a dot-separated JSONPath string,
with array indices attached directly (no dot before brackets).pathOf(const ctx: Proxied<State>ctx.bucket: Ref<string>bucket); // '$.bucket'
function pathOf(ref: Ref<unknown>): stringExtracts the JSONPath string from a Ref.
Converts the internal path segments into a dot-separated JSONPath string,
with array indices attached directly (no dot before brackets).pathOf(const ctx: Proxied<State>ctx.mediaInfo: Proxied<{
width: number;
height: number;
}>
mediaInfo); // '$.mediaInfo'
function pathOf(ref: Ref<unknown>): stringExtracts the JSONPath string from a Ref.
Converts the internal path segments into a dot-separated JSONPath string,
with array indices attached directly (no dot before brackets).pathOf(const ctx: Proxied<State>ctx.mediaInfo: Proxied<{
width: number;
height: number;
}>
mediaInfo.width: Ref<number>width); // '$.mediaInfo.width'
Nesting has no depth limit — each access simply extends the path:
type type State = {
video: {
metadata: {
tracks: {
audio: {
codec: string;
};
};
};
};
}
State = {
video: {
metadata: {
tracks: {
audio: {
codec: string;
};
};
};
}
video: { metadata: {
tracks: {
audio: {
codec: string;
};
};
}
metadata: { tracks: {
audio: {
codec: string;
};
}
tracks: { audio: {
codec: string;
}
audio: { codec: stringcodec: string } } } };
};
const const ctx: Proxied<State>ctx = createProxy<State>(path?: string[]): Proxied<State>Creates a typed Proxy that records property access as JSONPath segments.
Every property access on the returned proxy returns a new proxy with
the property name appended to the path. Numeric keys (e.g. `[0]`) are
recorded as array index segments.createProxy<type State = {
video: {
metadata: {
tracks: {
audio: {
codec: string;
};
};
};
};
}
State>();
function pathOf(ref: Ref<unknown>): stringExtracts the JSONPath string from a Ref.
Converts the internal path segments into a dot-separated JSONPath string,
with array indices attached directly (no dot before brackets).pathOf(const ctx: Proxied<State>ctx.video: Proxied<{
metadata: {
tracks: {
audio: {
codec: string;
};
};
};
}>
video.metadata: Proxied<{
tracks: {
audio: {
codec: string;
};
};
}>
metadata.tracks: Proxied<{
audio: {
codec: string;
};
}>
tracks.audio: Proxied<{
codec: string;
}>
audio.codec: Ref<string>codec);
// '$.video.metadata.tracks.audio.codec'
Arrays and indexing
Numeric access becomes bracket notation, which is what JSONPath expects:
type type State = {
frames: {
url: string;
width: number;
}[];
}
State = { frames: {
url: string;
width: number;
}[]
frames: { url: stringurl: string; width: numberwidth: number }[] };
const const ctx: Proxied<State>ctx = createProxy<State>(path?: string[]): Proxied<State>Creates a typed Proxy that records property access as JSONPath segments.
Every property access on the returned proxy returns a new proxy with
the property name appended to the path. Numeric keys (e.g. `[0]`) are
recorded as array index segments.createProxy<type State = {
frames: {
url: string;
width: number;
}[];
}
State>();
function pathOf(ref: Ref<unknown>): stringExtracts the JSONPath string from a Ref.
Converts the internal path segments into a dot-separated JSONPath string,
with array indices attached directly (no dot before brackets).pathOf(const ctx: Proxied<State>ctx.frames: Proxied<{
url: string;
width: number;
}[]>
frames[0]); // '$.frames[0]'
function pathOf(ref: Ref<unknown>): stringExtracts the JSONPath string from a Ref.
Converts the internal path segments into a dot-separated JSONPath string,
with array indices attached directly (no dot before brackets).pathOf(const ctx: Proxied<State>ctx.frames: Proxied<{
url: string;
width: number;
}[]>
frames[0].url: Ref<string>url); // '$.frames[0].url'
function pathOf(ref: Ref<unknown>): stringExtracts the JSONPath string from a Ref.
Converts the internal path segments into a dot-separated JSONPath string,
with array indices attached directly (no dot before brackets).pathOf(const ctx: Proxied<State>ctx.frames: Proxied<{
url: string;
width: number;
}[]>
frames[2].width: Ref<number>width); // '$.frames[2].width'
Tuples keep per-index types
When the type is a tuple rather than an array, each index keeps its own type. This is what makes parallel work — branch outputs are a tuple, so ctx.process[0] and ctx.process[1] have different shapes:
type type ParallelOutput = [{
extractedFrames: string[];
}, {
transcodedUrl: string;
}]
ParallelOutput = [
{ extractedFrames: string[]extractedFrames: string[] },
{ transcodedUrl: stringtranscodedUrl: string }
];
const const ctx: Proxied<{
process: ParallelOutput;
}>
ctx = createProxy<{
process: ParallelOutput;
}>(path?: string[]): Proxied<{
process: ParallelOutput;
}>
Creates a typed Proxy that records property access as JSONPath segments.
Every property access on the returned proxy returns a new proxy with
the property name appended to the path. Numeric keys (e.g. `[0]`) are
recorded as array index segments.createProxy<{ process: ParallelOutputprocess: type ParallelOutput = [{
extractedFrames: string[];
}, {
transcodedUrl: string;
}]
ParallelOutput }>();
const frames = const ctx: Proxied<{
process: ParallelOutput;
}>
ctx.process: Proxied<ParallelOutput>process[0].extractedFrames: Proxied<string[]>extractedFrames;
const url = const ctx: Proxied<{
process: ParallelOutput;
}>
ctx.process: Proxied<ParallelOutput>process[1].transcodedUrl: Ref<string>transcodedUrl;
Reaching for ctx.process[1].extractedFrames is a compile error — index 1 has no such field.
Every level stays typed
Proxied<T> is defined recursively, so the type is preserved all the way down, and every level is also a Ref of whatever it points at:
type type State = {
count: number;
nested: {
flag: boolean;
items: string[];
};
}
State = {
count: numbercount: number;
nested: {
flag: boolean;
items: string[];
}
nested: { flag: booleanflag: boolean; items: string[]items: string[] };
};
const const ctx: Proxied<State>ctx = createProxy<State>(path?: string[]): Proxied<State>Creates a typed Proxy that records property access as JSONPath segments.
Every property access on the returned proxy returns a new proxy with
the property name appended to the path. Numeric keys (e.g. `[0]`) are
recorded as array index segments.createProxy<type State = {
count: number;
nested: {
flag: boolean;
items: string[];
};
}
State>();
const nested = const ctx: Proxied<State>ctx.nested: Proxied<{
flag: boolean;
items: string[];
}>
nested;
const flag = const ctx: Proxied<State>ctx.nested: Proxied<{
flag: boolean;
items: string[];
}>
nested.flag: Ref<boolean>flag;
Proxies are immutable path builders
Accessing a property never mutates the proxy it was accessed from — each access returns a fresh one. So a ref can be captured and reused without any risk of its path drifting:
type type State = {
a: {
b: string;
};
}
State = { a: {
b: string;
}
a: { b: stringb: string } };
const const ctx: Proxied<State>ctx = createProxy<State>(path?: string[]): Proxied<State>Creates a typed Proxy that records property access as JSONPath segments.
Every property access on the returned proxy returns a new proxy with
the property name appended to the path. Numeric keys (e.g. `[0]`) are
recorded as array index segments.createProxy<type State = {
a: {
b: string;
};
}
State>();
const const aRef: Proxied<{
b: string;
}>
aRef = const ctx: Proxied<State>ctx.a: Proxied<{
b: string;
}>
a;
const const bRef: Ref<string>bRef = const ctx: Proxied<State>ctx.a: Proxied<{
b: string;
}>
a.b: Ref<string>b;
function pathOf(ref: Ref<unknown>): stringExtracts the JSONPath string from a Ref.
Converts the internal path segments into a dot-separated JSONPath string,
with array indices attached directly (no dot before brackets).pathOf(const ctx: Proxied<State>ctx); // still '$'
function pathOf(ref: Ref<unknown>): stringExtracts the JSONPath string from a Ref.
Converts the internal path segments into a dot-separated JSONPath string,
with array indices attached directly (no dot before brackets).pathOf(const aRef: Proxied<{
b: string;
}>
aRef); // '$.a'
function pathOf(ref: Ref<unknown>): stringExtracts the JSONPath string from a Ref.
Converts the internal path segments into a dot-separated JSONPath string,
with array indices attached directly (no dot before brackets).pathOf(const bRef: Ref<string>bRef); // '$.a.b'