From 07b33771e3315a2aa77dad40348f27c72ec58f55 Mon Sep 17 00:00:00 2001 From: LeCarbonator <18158911+LeCarbonator@users.noreply.github.com> Date: Thu, 5 Jun 2025 18:03:28 +0200 Subject: [PATCH] fix(form-core): fix DeepValue from record values being wrong --- packages/form-core/src/util-types.ts | 35 ++++++++++++------ packages/form-core/tests/util-types.test-d.ts | 36 +++++++++++++++++++ 2 files changed, 60 insertions(+), 11 deletions(-) diff --git a/packages/form-core/src/util-types.ts b/packages/form-core/src/util-types.ts index 4049e1cbe..9aa71ee57 100644 --- a/packages/form-core/src/util-types.ts +++ b/packages/form-core/src/util-types.ts @@ -150,8 +150,18 @@ export type DeepKeysAndValuesImpl< ? DeepKeyAndValueObject : TAcc -export type DeepRecord = { - [TRecord in DeepKeysAndValues as TRecord['key']]: TRecord['value'] +type DeepRecordWithDynamicSuffix = { + // DeepKeys uses a dot as reserved character, so the only way that it can be a suffix + // is if the suffix is a dynamic variable. + [TRecord in DeepKeysAndValues as `${TRecord['key']}.` extends TRecord['key'] + ? TRecord['key'] + : never]: TRecord['value'] +} + +type DeepRecordWithStaticSuffix = { + [TRecord in DeepKeysAndValues as `${TRecord['key']}.` extends TRecord['key'] + ? never + : TRecord['key']]: TRecord['value'] } /** @@ -161,15 +171,6 @@ export type DeepKeys = unknown extends T ? string : DeepKeysAndValues['key'] -/** - * Infer the type of a deeply nested property within an object or an array. - */ -export type DeepValue = unknown extends TValue - ? TValue - : TAccessor extends DeepKeys - ? DeepRecord[TAccessor] - : never - /** * The keys of an object or array, deeply nested and only with a value of TValue */ @@ -177,3 +178,15 @@ export type DeepKeysOfType = Extract< DeepKeysAndValues, AnyDeepKeyAndValue >['key'] + +type PickValue = T[K] +/** + * Infer the type of a deeply nested property within an object or an array. + */ +export type DeepValue = unknown extends TValue + ? TValue + : TAccessor extends keyof DeepRecordWithStaticSuffix + ? PickValue, TAccessor> + : TAccessor extends keyof DeepRecordWithDynamicSuffix + ? PickValue, TAccessor> + : never diff --git a/packages/form-core/tests/util-types.test-d.ts b/packages/form-core/tests/util-types.test-d.ts index 67086c745..813f6b50e 100644 --- a/packages/form-core/tests/util-types.test-d.ts +++ b/packages/form-core/tests/util-types.test-d.ts @@ -446,3 +446,39 @@ type AnyObjectExample4 = DeepValue expectTypeOf(0 as never as AnyObjectExample4).toEqualTypeOf() type AnyObjectExample5 = DeepValue expectTypeOf(0 as never as AnyObjectExample5).toEqualTypeOf() + +type RecordExample = { + records: Record +} + +expectTypeOf>().toEqualTypeOf< + | 'records' + | `records.${string}` + | `records.${string}.a` + | `records.${string}.b` + | `records.${string}.c` + | `records.${string}.c.d` +>() +expectTypeOf>().toEqualTypeOf< + `records.${string}.a` | `records.${string}.c.d` +>() +expectTypeOf>().toEqualTypeOf< + Record +>() +expectTypeOf>().toEqualTypeOf<{ + a: string + b: number + c: { d: string } +}>() +expectTypeOf< + DeepValue +>().toEqualTypeOf() +expectTypeOf< + DeepValue +>().toEqualTypeOf() +expectTypeOf>().toEqualTypeOf<{ + d: string +}>() +expectTypeOf< + DeepValue +>().toEqualTypeOf()