@@ -27,53 +27,154 @@ export const createEndpoint = Symbol("Comlink.endpoint");
2727export const releaseProxy = Symbol ( "Comlink.releaseProxy" ) ;
2828const throwMarker = Symbol ( "Comlink.thrown" ) ;
2929
30- // prettier-ignore
31- type Promisify < T > =
32- T extends { [ proxyMarker ] : boolean }
33- ? Promise < Remote < T > >
34- : T extends ( ...args : infer R1 ) => infer R2
35- ? ( ...args : R1 ) => Promisify < R2 >
36- : Promise < T > ;
30+ /**
31+ * Interface of values that were marked to be proxied with `comlink.proxy()`.
32+ * Can also be implemented by classes.
33+ */
34+ export interface ProxyMarked {
35+ [ proxyMarker ] : true ;
36+ }
37+
38+ /**
39+ * Takes a type and wraps it in a Promise, if it not already is one.
40+ * This is to avoid `Promise<Promise<T>>`.
41+ *
42+ * This is the inverse of `Unpromisify<T>`.
43+ */
44+ type Promisify < T > = T extends Promise < unknown > ? T : Promise < T > ;
45+ /**
46+ * Takes a type that may be Promise and unwraps the Promise type.
47+ * If `P` is not a Promise, it returns `P`.
48+ *
49+ * This is the inverse of `Promisify<T>`.
50+ */
51+ type Unpromisify < P > = P extends Promise < infer T > ? T : P ;
52+
53+ /**
54+ * Takes the raw type of a remote property and returns the type that is visible to the local thread on the proxy.
55+ *
56+ * Note: This needs to be its own type alias, otherwise it will not distribute over unions.
57+ * See https://www.typescriptlang.org/docs/handbook/advanced-types.html#distributive-conditional-types
58+ */
59+ type RemoteProperty < T > =
60+ // If the value is a method, comlink will proxy it automatically.
61+ // Objects are only proxied if they are marked to be proxied.
62+ // Otherwise, the property is converted to a Promise that resolves the cloned value.
63+ T extends Function | ProxyMarked ? Remote < T > : Promisify < T > ;
64+
65+ /**
66+ * Takes the raw type of a property as a remote thread would see it through a proxy (e.g. when passed in as a function
67+ * argument) and returns the type that the local thread has to supply.
68+ *
69+ * This is the inverse of `RemoteProperty<T>`.
70+ *
71+ * Note: This needs to be its own type alias, otherwise it will not distribute over unions. See
72+ * https://www.typescriptlang.org/docs/handbook/advanced-types.html#distributive-conditional-types
73+ */
74+ type LocalProperty < T > = T extends Function | ProxyMarked
75+ ? Local < T >
76+ : Unpromisify < T > ;
77+
78+ /**
79+ * Proxies `T` if it is a `ProxyMarked`, clones it otherwise (as handled by structured cloning and transfer handlers).
80+ */
81+ export type ProxyOrClone < T > = T extends ProxyMarked ? Remote < T > : T ;
82+ /**
83+ * Inverse of `ProxyOrClone<T>`.
84+ */
85+ export type UnproxyOrClone < T > = T extends RemoteObject < ProxyMarked >
86+ ? Local < T >
87+ : T ;
3788
38- // prettier-ignore
89+ /**
90+ * Takes the raw type of a remote object in the other thread and returns the type as it is visible to the local thread
91+ * when proxied with `Comlink.proxy()`.
92+ *
93+ * This does not handle call signatures, which is handled by the more general `Remote<T>` type.
94+ *
95+ * @template T The raw type of a remote object as seen in the other thread.
96+ */
97+ export type RemoteObject < T > = { [ P in keyof T ] : RemoteProperty < T [ P ] > } ;
98+ /**
99+ * Takes the type of an object as a remote thread would see it through a proxy (e.g. when passed in as a function
100+ * argument) and returns the type that the local thread has to supply.
101+ *
102+ * This does not handle call signatures, which is handled by the more general `Local<T>` type.
103+ *
104+ * This is the inverse of `RemoteObject<T>`.
105+ *
106+ * @template T The type of a proxied object.
107+ */
108+ export type LocalObject < T > = { [ P in keyof T ] : LocalProperty < T [ P ] > } ;
109+
110+ /**
111+ * Additional special comlink methods available on each proxy returned by `Comlink.wrap()`.
112+ */
113+ export interface ProxyMethods {
114+ [ createEndpoint ] : ( ) => Promise < MessagePort > ;
115+ [ releaseProxy ] : ( ) => void ;
116+ }
117+
118+ /**
119+ * Takes the raw type of a remote object, function or class in the other thread and returns the type as it is visible to
120+ * the local thread from the proxy return value of `Comlink.wrap()` or `Comlink.proxy()`.
121+ */
39122export type Remote < T > =
40- (
41- T extends ( ...args : infer R1 ) => infer R2
42- ? ( ...args : R1 ) => Promisify < R2 >
43- : unknown
44- ) &
45- (
46- T extends { new ( ...args : infer R1 ) : infer R2 }
47- ? { new ( ...args : R1 ) : Promise < Remote < R2 > > }
48- : unknown
49- ) &
50- (
51- T extends Object
52- ? { [ K in keyof T ] : Remote < T [ K ] > }
53- : unknown
54- ) &
55- (
56- T extends string
57- ? Promise < string >
58- : unknown
59- ) &
60- (
61- T extends number
62- ? Promise < number >
63- : unknown
64- ) &
65- (
66- T extends boolean
67- ? Promise < boolean >
68- : unknown
69- ) & {
70- [ createEndpoint ] : ( ) => Promise < MessagePort > ;
71- [ releaseProxy ] : ( ) => void ;
72- } ;
123+ // Handle properties
124+ RemoteObject < T > &
125+ // Handle call signature (if present)
126+ ( T extends ( ...args : infer TArguments ) => infer TReturn
127+ ? (
128+ ...args : { [ I in keyof TArguments ] : UnproxyOrClone < TArguments [ I ] > }
129+ ) => Promisify < ProxyOrClone < Unpromisify < TReturn > > >
130+ : unknown ) &
131+ // Handle construct signature (if present)
132+ // The return of construct signatures is always proxied (whether marked or not)
133+ ( T extends { new ( ...args : infer TArguments ) : infer TInstance }
134+ ? {
135+ new (
136+ ...args : {
137+ [ I in keyof TArguments ] : UnproxyOrClone < TArguments [ I ] > ;
138+ }
139+ ) : Promisify < Remote < TInstance > > ;
140+ }
141+ : unknown ) &
142+ // Include additional special comlink methods available on the proxy.
143+ ProxyMethods ;
73144
74- declare var x : Remote < number > ;
145+ /**
146+ * Expresses that a type can be either a sync or async.
147+ */
148+ type MaybePromise < T > = Promise < T > | T ;
75149
76- declare var y : PromiseLike < number > ;
150+ /**
151+ * Takes the raw type of a remote object, function or class as a remote thread would see it through a proxy (e.g. when
152+ * passed in as a function argument) and returns the type the local thread has to supply.
153+ *
154+ * This is the inverse of `Remote<T>`. It takes a `Remote<T>` and returns its original input `T`.
155+ */
156+ export type Local < T > =
157+ // Omit the special proxy methods (they don't need to be supplied, comlink adds them)
158+ Omit < LocalObject < T > , keyof ProxyMethods > &
159+ // Handle call signatures (if present)
160+ ( T extends ( ...args : infer TArguments ) => infer TReturn
161+ ? (
162+ ...args : { [ I in keyof TArguments ] : ProxyOrClone < TArguments [ I ] > }
163+ ) => // The raw function could either be sync or async, but is always proxied automatically
164+ MaybePromise < UnproxyOrClone < Unpromisify < TReturn > > >
165+ : unknown ) &
166+ // Handle construct signature (if present)
167+ // The return of construct signatures is always proxied (whether marked or not)
168+ ( T extends { new ( ...args : infer TArguments ) : infer TInstance }
169+ ? {
170+ new (
171+ ...args : {
172+ [ I in keyof TArguments ] : ProxyOrClone < TArguments [ I ] > ;
173+ }
174+ ) : // The raw constructor could either be sync or async, but is always proxied automatically
175+ MaybePromise < Local < Unpromisify < TInstance > > > ;
176+ }
177+ : unknown ) ;
77178
78179export interface TransferHandler {
79180 canHandle ( obj : any ) : boolean ;
@@ -314,7 +415,7 @@ export function transfer(obj: any, transfers: Transferable[]) {
314415 return obj ;
315416}
316417
317- export function proxy < T > ( obj : T ) : T & { [ proxyMarker ] : true } {
418+ export function proxy < T > ( obj : T ) : T & ProxyMarked {
318419 return Object . assign ( obj , { [ proxyMarker ] : true } ) as any ;
319420}
320421
0 commit comments