Skip to content

Commit e05ac5a

Browse files
thomasballingerConvex, Inc.
authored andcommitted
Test behavior of wrapper argument inference (#30271)
Add tests for argument and return value inference for function wrappers. This could be helpful for assessing the impact of a change to this behavior in the future, e.g. to solve cyclic inference issues. GitOrigin-RevId: 82741de258692fb9a8800fa652ebbd578d8d7936
1 parent 44ecde9 commit e05ac5a

File tree

1 file changed

+88
-0
lines changed

1 file changed

+88
-0
lines changed

src/server/registration.test.ts

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,94 @@ describe("argument inference", () => {
279279
});
280280
});
281281

282+
describe("argument inference 2: args and validators", () => {
283+
// Test with mutation, but all the wrappers work the same way.
284+
const mutation: MutationBuilder<any, "public"> = (() => {
285+
// Intentional noop. We're only testing the type
286+
}) as any;
287+
288+
const module = {
289+
argsSubtypeOfArgsValidator: mutation({
290+
args: { foo: v.string() },
291+
handler: (_, { foo }: { foo: string | number }) => 1,
292+
}),
293+
argsSupertypeOfArgsValidator: mutation({
294+
args: { foo: v.union(v.string(), v.number()) },
295+
handler: (_, { foo }: { foo: string }) => 1,
296+
}),
297+
argsPartiallyIntersectArgsValidator: mutation({
298+
args: { foo: v.union(v.string(), v.number()) },
299+
// @ts-expect-error when neither type is a subtype of the other, error
300+
handler: (_, { foo }: { foo: string | Array<number> }) => 1,
301+
}),
302+
argsDontIntersectArgsValidator: mutation({
303+
args: { foo: v.string() },
304+
// @ts-expect-error when neither type is a subtype of the other, error
305+
handler: (_, { foo }: { foo: number }) => 1,
306+
}),
307+
};
308+
309+
type API = ApiFromModules<{ module: typeof module }>;
310+
311+
// If the validator is more specific, that's the type that will be used.
312+
// That seems right.
313+
test("Handler args are a subtype of args validator", () => {
314+
type Args = API["module"]["argsSubtypeOfArgsValidator"]["_args"];
315+
assert<Equals<Args, { foo: string }>>();
316+
});
317+
// If the argument type is more specific, that's the type used.
318+
// It would be nice to change this. If the validator type
319+
// could entirely determine the inferred type on the client
320+
// then you could skip the function for inference!
321+
test("Handler args are a supertype of args validator", () => {
322+
type Args = API["module"]["argsSupertypeOfArgsValidator"]["_args"];
323+
assert<Equals<Args, { foo: string }>>();
324+
});
325+
});
326+
327+
describe("argument inference 3: outputs and validators", () => {
328+
// Test with mutation, but all the wrappers work the same way.
329+
const mutation: MutationBuilder<any, "public"> = (() => {
330+
// Intentional noop. We're only testing the type
331+
}) as any;
332+
333+
const module = {
334+
returnSubtypeOfReturnsValidator: mutation({
335+
returns: v.string(),
336+
handler: (_) => "a" as const,
337+
}),
338+
returnSupertypeOfReturnsValidator: mutation({
339+
returns: v.literal("a"),
340+
// @ts-expect-error when return value is not a subtype of validator, error
341+
handler: (_) => "b" as "b" | "a",
342+
}),
343+
returnPartiallyIntersectReturnsValidator: mutation({
344+
returns: v.union(v.literal("a"), v.literal("b")),
345+
// @ts-expect-error when return value is not a subtype of validator, error
346+
handler: (_) => "b" as "b" | "c",
347+
}),
348+
returnDoesntIntersectReturnsValidator: mutation({
349+
returns: v.literal("a"),
350+
// @ts-expect-error when neither type is a subtype of the other, error
351+
handler: (_) => "b" as const,
352+
}),
353+
};
354+
355+
type API = ApiFromModules<{ module: typeof module }>;
356+
357+
// Output validators seem to work about right.
358+
test("Handler return value is a subtype of returns validator", () => {
359+
type ReturnType =
360+
API["module"]["returnSubtypeOfReturnsValidator"]["_returnType"];
361+
assert<Equals<ReturnType, "a">>();
362+
});
363+
test("Handler return value is a supertype of returns validator", () => {
364+
type ReturnType =
365+
API["module"]["returnSupertypeOfReturnsValidator"]["_returnType"];
366+
assert<Equals<ReturnType, any>>();
367+
});
368+
});
369+
282370
describe("argument and return value validators can be objects or validators", () => {
283371
// Test with mutation, we aim for all the wrappers work the same way.
284372
const mutation: MutationBuilder<any, "public"> = mutationGeneric;

0 commit comments

Comments
 (0)