Repository: colinhacks/zod (TypeScript)

Issue:
v4: `z.object().check()` types the `value` property as `any`
Using `@zod/mini` version `4.0.0-beta.20250505T195954`, the the following code has incorrect type information for the check function:

```typescript
const Thing = z.object({
  name: z.string(),
  age: z.number()
}).check(({ value, issues }) => {
});

type ThingOutput = z.infer<typeof Thing> // { name: string; age: number }
type ThingInput = z.input<typeof Thing> // { name: string; age: number }
```

<img width="265" alt="Image" src="https://github.com/user-attachments/assets/85f9ed00-4b7d-4cfe-b6ca-763cc99b753d" />

With the previous beta, `z.interface()` would give the correct type for `value`.


Discussion:
We can temporarily fix that with a `zod.d.ts` (or whatever you want):
```ts
import "zod/v4-mini";
import type { core } from "zod/v4-mini";

declare module "zod/v4-mini" {
  export interface ZodMiniType {
    check(...checks: (core.CheckFn<core.output<this>> | core.$ZodCheck<core.output<this>>)[]): this;
  }
}
```
(I have submitted a PR)
 @rphlmr Thank you for fixing that as well as providing a work-around!
For anyone else experiencing this, I adapted the solution @rphlmr gave to my application. I have one schema module and added this to the top of that module:

```typescript
import * as z from '@zod/mini';

// TODO: remove after https://github.com/colinhacks/zod/pull/4568 lands
declare module '@zod/mini' {
  export interface ZodMiniType {
    check(
      ...checks: (z.core.CheckFn<z.core.output<this>> | z.core.$ZodCheck<z.core.output<this>>)[]
    ): this;
  }
}
```



Patch:
diff --git a/packages/docs/content/error-formatting.mdx b/packages/docs/content/error-formatting.mdx
index 05e127385f..e803185afe 100644
--- a/packages/docs/content/error-formatting.mdx
+++ b/packages/docs/content/error-formatting.mdx
@@ -150,7 +150,6 @@ This returns the following string:
 
 ## `z.flattenError()`
 
-
 While `z.treeifyError()` is useful for traversing a potentially complex nested structure, the majority of schemas are *flat*—just one level deep. In this case, use `z.flattenError()` to retrieve a clean, shallow error object.
 
 ```ts
diff --git a/packages/zod/src/v4/classic/schemas.ts b/packages/zod/src/v4/classic/schemas.ts
index 99a7e15064..7b4f5347b0 100644
--- a/packages/zod/src/v4/classic/schemas.ts
+++ b/packages/zod/src/v4/classic/schemas.ts
@@ -56,7 +56,7 @@ export interface ZodType<out Output = unknown, out Input = unknown> extends core
   refine(check: (arg: core.output<this>) => unknown | Promise<unknown>, params?: string | core.$ZodCustomParams): this;
   /** @deprecated Use `.check()` instead. */
   superRefine(
-    refinement: (arg: core.output<this>, ctx: RefinementCtx<this["_zod"]["output"]>) => void | Promise<void>
+    refinement: (arg: core.output<this>, ctx: RefinementCtx<core.output<this>>) => void | Promise<void>
   ): this;
   overwrite(fn: (x: core.output<this>) => core.output<this>): this;
 
@@ -77,8 +77,8 @@ export interface ZodType<out Output = unknown, out Input = unknown> extends core
   ): ZodPipe<this, ZodTransform<Awaited<NewOut>, core.output<this>>>;
   catch(def: core.output<this>): ZodCatch<this>;
   catch(def: (ctx: core.$ZodCatchCtx) => core.output<this>): ZodCatch<this>;
-  pipe<T extends core.$ZodType<any, this["_zod"]["output"]>>(
-    target: T | core.$ZodType<any, this["_zod"]["output"]>
+  pipe<T extends core.$ZodType<any, core.output<this>>>(
+    target: T | core.$ZodType<any, core.output<this>>
   ): ZodPipe<this, T>;
   readonly(): ZodReadonly<this>;
 
diff --git a/packages/zod/src/v4/core/function.ts b/packages/zod/src/v4/core/function.ts
index 72a73c8071..544fe1a068 100644
--- a/packages/zod/src/v4/core/function.ts
+++ b/packages/zod/src/v4/core/function.ts
@@ -1,5 +1,5 @@
 import { _array, _tuple, _unknown } from "./api.js";
-
+import type * as core from "./core.js";
 import { parse, parseAsync } from "./parse.js";
 import * as schemas from "./schemas.js";
 import { $ZodTuple } from "./schemas.js";
@@ -26,20 +26,20 @@ export type $ZodFunctionIn = $ZodFunctionArgs;
 export type $ZodFunctionOut = schemas.$ZodType;
 
 export type $InferInnerFunctionType<Args extends $ZodFunctionIn, Returns extends $ZodFunctionOut> = (
-  ...args: $ZodFunctionIn extends Args ? never[] : Args["_zod"]["output"]
-) => Returns["_zod"]["input"];
+  ...args: $ZodFunctionIn extends Args ? never[] : core.output<Args>
+) => core.input<Returns>;
 
 export type $InferInnerFunctionTypeAsync<Args extends $ZodFunctionIn, Returns extends $ZodFunctionOut> = (
-  ...args: $ZodFunctionIn extends Args ? never[] : Args["_zod"]["output"]
-) => util.MaybeAsync<Returns["_zod"]["input"]>;
+  ...args: $ZodFunctionIn extends Args ? never[] : core.output<Args>
+) => util.MaybeAsync<core.input<Returns>>;
 
 export type $InferOuterFunctionType<Args extends $ZodFunctionIn, Returns extends $ZodFunctionOut> = (
-  ...args: $ZodFunctionIn extends Args ? never[] : Args["_zod"]["input"]
-) => Returns["_zod"]["output"];
+  ...args: $ZodFunctionIn extends Args ? never[] : core.input<Args>
+) => core.output<Returns>;
 
 export type $InferOuterFunctionTypeAsync<Args extends $ZodFunctionIn, Returns extends $ZodFunctionOut> = (
-  ...args: $ZodFunctionIn extends Args ? never[] : Args["_zod"]["input"]
-) => util.MaybeAsync<Returns["_zod"]["output"]>;
+  ...args: $ZodFunctionIn extends Args ? never[] : core.input<Args>
+) => util.MaybeAsync<core.output<Returns>>;
 
 export class $ZodFunction<
   Args extends $ZodFunctionIn = $ZodFunctionIn,
diff --git a/packages/zod/src/v4/mini/schemas.ts b/packages/zod/src/v4/mini/schemas.ts
index e57fec972a..79401c34a6 100644
--- a/packages/zod/src/v4/mini/schemas.ts
+++ b/packages/zod/src/v4/mini/schemas.ts
@@ -5,7 +5,7 @@ import * as parse from "./parse.js";
 type SomeType = core.$ZodType;
 
 export interface ZodMiniType<out Output = unknown, out Input = unknown> extends core.$ZodType<Output, Input> {
-  check(...checks: (core.CheckFn<this["_zod"]["output"]> | core.$ZodCheck<this["_zod"]["output"]>)[]): this;
+  check(...checks: (core.CheckFn<core.output<this>> | core.$ZodCheck<core.output<this>>)[]): this;
   clone(def?: this["_zod"]["def"], params?: { parent: boolean }): this;
   register<R extends core.$ZodRegistry>(
     registry: R,
diff --git a/play.ts b/play.ts
index cc813f68e7..3825cb0544 100644
--- a/play.ts
+++ b/play.ts
@@ -1,15 +1,10 @@
-import { z } from "zod/v4";
+import { z } from "zod/v4-mini";
 
-const User = z.string().optional();
-
-console.dir(z.toJSONSchema(User), { depth: null });
-// => {
-//   type: 'object',
-//   properties: { name: { type: 'string' }, friend: { '$ref': '#' } },
-//   required: [ 'name', 'friend' ]
-//   additionalProperties: false
-// }
-
-z.toJSONSchema(z.globalRegistry, {
-  uri: (id) => `https://example.com/${id}.json`,
-});
+const Thing = z
+  .object({
+    name: z.string(),
+    age: z.number(),
+  })
+  .check(({ value, issues }) => {
+    value; // => any
+  });


Test patch:
diff --git a/packages/zod/src/v4/mini/tests/object.test.ts b/packages/zod/src/v4/mini/tests/object.test.ts
index 24c422e657..2d35484572 100644
--- a/packages/zod/src/v4/mini/tests/object.test.ts
+++ b/packages/zod/src/v4/mini/tests/object.test.ts
@@ -36,6 +36,21 @@ test("z.object", () => {
   expect(schema.parse(obj)).toEqual({ a: "foo" });
 });
 
+test("z.object().check()", () => {
+  const a = z.object({
+    name: z.string(),
+    age: z.number(),
+    points: z.optional(z.number()),
+    "test?": z.boolean(),
+  });
+
+  type a = z.output<typeof a>;
+
+  a.check(({ value }) => {
+    expectTypeOf(value).toEqualTypeOf<a>();
+  });
+});
+
 test("z.strictObject", () => {
   const a = z.strictObject({
     name: z.string(),