From e3af80d2acb7028f7dad1fc24233cc48528910ca Mon Sep 17 00:00:00 2001 From: tsushanth <78000697+tsushanth@users.noreply.github.com> Date: Tue, 30 Jun 2026 09:12:21 -0700 Subject: [PATCH] fix(form-core): check StandardSchemaV1 before FieldValidateFn in UnwrapFieldValidateOrFn Arktype's `Type` implements `Callable` which makes it structurally extend `(data: unknown) => T`. TypeScript's contravariant parameter check means `ArkType extends FieldValidateFn` evaluates to `true` (the param check reduces to `{value:any,...} extends unknown`), so the `StandardSchemaV1` branch was never reached and `errors` entries resolved to `ReturnType` instead of `StandardSchemaV1Issue[]`. Fix: check `StandardSchemaV1` first on both the field and form-group branches of `UnwrapFieldValidateOrFn`. Schemas that happen to be callable (arktype, and future StandardSchema implementations) now take the correct path; plain function validators still fall through to the `FieldValidateFn` branch as before. Adds a type-level test asserting that an arktype `type('string>0')` field validator produces `StandardSchemaV1Issue[] | undefined` errors, not the arktype output type. Fixes #2221 --- packages/form-core/src/types.ts | 20 ++++++++--------- .../tests/standardSchemaValidator.test-d.ts | 22 +++++++++++++++++++ 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/packages/form-core/src/types.ts b/packages/form-core/src/types.ts index 62513afc2..e02a4e2af 100644 --- a/packages/form-core/src/types.ts +++ b/packages/form-core/src/types.ts @@ -452,17 +452,17 @@ export type UnwrapFieldValidateOrFn< : undefined : undefined : never) - | ([TValidateOrFn] extends [FieldValidateFn] - ? ReturnType - : [TValidateOrFn] extends [StandardSchemaV1] - ? // TODO: Check if `disableErrorFlat` is enabled, if so, return StandardSchemaV1Issue[][] - StandardSchemaV1Issue[] + | ([TValidateOrFn] extends [StandardSchemaV1] + ? // TODO: Check if `disableErrorFlat` is enabled, if so, return StandardSchemaV1Issue[][] + StandardSchemaV1Issue[] + : [TValidateOrFn] extends [FieldValidateFn] + ? ReturnType : undefined) - | ([TValidateOrFn] extends [FormGroupValidateFn] - ? ReturnType - : [TValidateOrFn] extends [StandardSchemaV1] - ? // TODO: Check if `disableErrorFlat` is enabled, if so, return StandardSchemaV1Issue[][] - StandardSchemaV1Issue[] + | ([TValidateOrFn] extends [StandardSchemaV1] + ? // TODO: Check if `disableErrorFlat` is enabled, if so, return StandardSchemaV1Issue[][] + StandardSchemaV1Issue[] + : [TValidateOrFn] extends [FormGroupValidateFn] + ? ReturnType : undefined) /** diff --git a/packages/form-core/tests/standardSchemaValidator.test-d.ts b/packages/form-core/tests/standardSchemaValidator.test-d.ts index 2543ec48a..9b32cc105 100644 --- a/packages/form-core/tests/standardSchemaValidator.test-d.ts +++ b/packages/form-core/tests/standardSchemaValidator.test-d.ts @@ -1,5 +1,6 @@ import { describe, expectTypeOf, it } from 'vitest' import { z } from 'zod' +import { type } from 'arktype' import { FieldApi, FormApi, standardSchemaValidators } from '../src/index' import type { StandardSchemaV1Issue } from '../src/index' @@ -80,6 +81,27 @@ describe('standard schema validator', () => { >() }) + it('Should infer StandardSchemaV1Issue[] for arktype field validators (issue #2221)', () => { + const schema = type({ firstName: 'string>0' }) + const form = new FormApi({ + defaultValues: { + firstName: '', + }, + }) + + const field = new FieldApi({ + form, + name: 'firstName', + validators: { + onChange: type('string>0'), + }, + }) + + expectTypeOf(field.getMeta().errorMap.onChange).toEqualTypeOf< + undefined | StandardSchemaV1Issue[] + >() + }) + it('Should return different Standard Schema Issue types from validateAsync based on scope', () => { const formSourceError = standardSchemaValidators.validateAsync( { value: '', validationSource: 'form' },