@payfit/unity-components
Version:
57 lines (56 loc) • 2.93 kB
TypeScript
/**
* Mirrors a form submit value shape while allowing each nested value to be
* initialized with `undefined`.
*
* TanStack Form `defaultValues` often describe an incomplete form state: a
* field can start empty even when the validated submit payload requires it.
* This type keeps the submit schema as the source of truth while making those
* empty initial field values type-safe.
*/
type DeepAllowUndefined<T> = T extends Array<infer Item> ? Array<DeepAllowUndefined<Item>> | undefined : T extends object ? {
[K in keyof T]: DeepAllowUndefined<T[K]> | undefined;
} : T | undefined;
/**
* Makes one path required again after `DeepAllowUndefined` allowed `undefined`
* throughout the value shape.
*
* Paths are expressed as tuples of object keys. Use `number` to target every
* item in an array, for example `['answers', number, 'questionId']`.
*/
type KeepRequiredAtPath<T, Path extends readonly unknown[]> = Path extends [] ? Exclude<T, undefined> : T extends Array<infer Item> ? Path extends [number, ...infer Rest extends readonly unknown[]] ? Array<KeepRequiredAtPath<Item, Rest>> : T : Path extends [
infer Key extends keyof T,
...infer Rest extends readonly unknown[]
] ? Omit<T, Key> & {
[K in Key]-?: KeepRequiredAtPath<Exclude<T[Key], undefined>, Rest>;
} : T;
/**
* Applies `KeepRequiredAtPath` to several paths.
*
* This is useful when some containers or technical identifiers must always be
* present in `defaultValues`, while regular user-input fields can still start
* as `undefined`.
*/
type KeepRequiredAtPaths<T, Paths extends ReadonlyArray<readonly unknown[]>> = Paths extends readonly [
infer Path extends readonly unknown[],
...infer Rest extends ReadonlyArray<readonly unknown[]>
] ? KeepRequiredAtPaths<KeepRequiredAtPath<T, Path>, Rest> : T;
/**
* Helper type for TanStack Form `defaultValues`.
*
* It starts from the final submit values, allows `undefined` throughout the
* default form state, then re-requires the paths listed in `RequiredPaths`.
*
* We created it to avoid maintaining a separate default-values type or using
* unsafe casts when default values are intentionally less complete than the
* validated submit payload.
*/
export type TanstackFormDefaultValues<SubmitValues, RequiredPaths extends ReadonlyArray<readonly unknown[]> = []> = KeepRequiredAtPaths<DeepAllowUndefined<SubmitValues>, RequiredPaths>;
/**
* Runtime no-op used to type-check TanStack Form default values.
*
* The function returns the provided value unchanged. Its purpose is to make
* object literals satisfy `TanstackFormDefaultValues` at compile time while
* keeping call sites compact.
*/
export declare function tanstackFormDefaultValues<SubmitValues, RequiredPaths extends ReadonlyArray<readonly unknown[]> = []>(value: TanstackFormDefaultValues<SubmitValues, RequiredPaths>): KeepRequiredAtPaths<DeepAllowUndefined<SubmitValues>, RequiredPaths>;
export {};