Skip to content

Commit

Permalink
Improve types inside generic functions
Browse files Browse the repository at this point in the history
  • Loading branch information
colinhacks committed Mar 6, 2023
1 parent 4d016b7 commit f9895ab
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 38 deletions.
21 changes: 9 additions & 12 deletions deno/lib/__tests__/generics.test.ts
Expand Up @@ -8,21 +8,18 @@ import * as z from "../index.ts";
test("generics", () => {
async function stripOuter<TData extends z.ZodTypeAny>(
schema: TData,
url: string
): Promise<TData["_output"]> {
const zStrippedResponse = z
data: unknown
) {
return z
.object({
topLevelKey: schema,
nested: schema, // as z.ZodTypeAny,
})
.transform((data) => {
return data.topLevelKey;
});

return fetch(url)
.then((response) => response.json())
.then((data) => zStrippedResponse.parse(data));
return data.nested!;
})
.parse({ nested: data });
}

const result = stripOuter(z.number(), "");
util.assertEqual<typeof result, Promise<number>>(true);
const result = stripOuter(z.object({ a: z.string() }), { a: "asdf" });
util.assertEqual<typeof result, Promise<{ a: string }>>(true);
});
11 changes: 9 additions & 2 deletions deno/lib/helpers/util.ts
Expand Up @@ -5,6 +5,7 @@ export namespace util {
? true
: false;

export type isAny<T> = 0 extends 1 & T ? true : false;
export const assertEqual = <A, B>(val: AssertEqual<A, B>) => val;
export function assertIs<T>(_arg: T): void {}
export function assertNever(_x: never): never {
Expand Down Expand Up @@ -107,8 +108,14 @@ export namespace objectUtil {
[k in keyof T]: undefined extends T[k] ? never : k;
}[keyof T];

export type addQuestionMarks<T extends object> = Partial<T> &
Pick<T, requiredKeys<T>>;
// type alkjsdf = addQuestionMarks<{ a: any }>;

export type addQuestionMarks<
T extends object,
R extends keyof T = requiredKeys<T>
// O extends keyof T = optionalKeys<T>
> = Pick<T, R> & Partial<T>;
// = { [k in O]?: T[k] } & { [k in R]: T[k] };

export type identity<T> = T;
export type flatten<T> = identity<{ [k in keyof T]: T[k] }>;
Expand Down
11 changes: 6 additions & 5 deletions deno/lib/types.ts
Expand Up @@ -2135,14 +2135,15 @@ export type objectOutputType<
Shape extends ZodRawShape,
Catchall extends ZodTypeAny,
UnknownKeys extends UnknownKeysParam = UnknownKeysParam
> = objectUtil.flatten<baseObjectOutputType<Shape>> &
> = objectUtil.flatten<
objectUtil.addQuestionMarks<baseObjectOutputType<Shape>>
> &
CatchallOutput<Catchall> &
PassthroughType<UnknownKeys>;

export type baseObjectOutputType<Shape extends ZodRawShape> =
objectUtil.addQuestionMarks<{
[k in keyof Shape]: Shape[k]["_output"];
}>;
export type baseObjectOutputType<Shape extends ZodRawShape> = {
[k in keyof Shape]: Shape[k]["_output"];
};

export type objectInputType<
Shape extends ZodRawShape,
Expand Down
21 changes: 9 additions & 12 deletions src/__tests__/generics.test.ts
Expand Up @@ -7,21 +7,18 @@ import * as z from "../index";
test("generics", () => {
async function stripOuter<TData extends z.ZodTypeAny>(
schema: TData,
url: string
): Promise<TData["_output"]> {
const zStrippedResponse = z
data: unknown
) {
return z
.object({
topLevelKey: schema,
nested: schema, // as z.ZodTypeAny,
})
.transform((data) => {
return data.topLevelKey;
});

return fetch(url)
.then((response) => response.json())
.then((data) => zStrippedResponse.parse(data));
return data.nested!;
})
.parse({ nested: data });
}

const result = stripOuter(z.number(), "");
util.assertEqual<typeof result, Promise<number>>(true);
const result = stripOuter(z.object({ a: z.string() }), { a: "asdf" });
util.assertEqual<typeof result, Promise<{ a: string }>>(true);
});
11 changes: 9 additions & 2 deletions src/helpers/util.ts
Expand Up @@ -5,6 +5,7 @@ export namespace util {
? true
: false;

export type isAny<T> = 0 extends 1 & T ? true : false;
export const assertEqual = <A, B>(val: AssertEqual<A, B>) => val;
export function assertIs<T>(_arg: T): void {}
export function assertNever(_x: never): never {
Expand Down Expand Up @@ -107,8 +108,14 @@ export namespace objectUtil {
[k in keyof T]: undefined extends T[k] ? never : k;
}[keyof T];

export type addQuestionMarks<T extends object> = Partial<T> &
Pick<T, requiredKeys<T>>;
// type alkjsdf = addQuestionMarks<{ a: any }>;

export type addQuestionMarks<
T extends object,
R extends keyof T = requiredKeys<T>
// O extends keyof T = optionalKeys<T>
> = Pick<T, R> & Partial<T>;
// = { [k in O]?: T[k] } & { [k in R]: T[k] };

export type identity<T> = T;
export type flatten<T> = identity<{ [k in keyof T]: T[k] }>;
Expand Down
11 changes: 6 additions & 5 deletions src/types.ts
Expand Up @@ -2135,14 +2135,15 @@ export type objectOutputType<
Shape extends ZodRawShape,
Catchall extends ZodTypeAny,
UnknownKeys extends UnknownKeysParam = UnknownKeysParam
> = objectUtil.flatten<baseObjectOutputType<Shape>> &
> = objectUtil.flatten<
objectUtil.addQuestionMarks<baseObjectOutputType<Shape>>
> &
CatchallOutput<Catchall> &
PassthroughType<UnknownKeys>;

export type baseObjectOutputType<Shape extends ZodRawShape> =
objectUtil.addQuestionMarks<{
[k in keyof Shape]: Shape[k]["_output"];
}>;
export type baseObjectOutputType<Shape extends ZodRawShape> = {
[k in keyof Shape]: Shape[k]["_output"];
};

export type objectInputType<
Shape extends ZodRawShape,
Expand Down

0 comments on commit f9895ab

Please sign in to comment.