Repository: react-hook-form/react-hook-form
File: src/types/path/eager.ts (TypeScript)

Code before:
import { FieldValues } from '../fields';
import {
  BrowserNativeObject,
  Primitive,
  UnPackAsyncDefaultValues,
} from '../utils';

import { ArrayKey, IsTuple, TupleKeys } from './common';

/**
 * Helper type for recursively constructing paths through a type.
 * See {@link Path}
 */
type PathImpl<K extends string | number, V, TraversedTypes> = V extends
  | Primitive
  | BrowserNativeObject
  ? `${K}`
  : V extends TraversedTypes
  ? [Extract<V, TraversedTypes>] extends [Extract<TraversedTypes, V>]
    ? `${K}`
    : `${K}` | `${K}.${Path<V, TraversedTypes | V>}`
  : `${K}` | `${K}.${Path<V, TraversedTypes | V>}`;

/**
 * Type which eagerly collects all paths through a type
 * @typeParam T - type which should be introspected
 * @typeParam TraversedTypes - types which have already been traversed to avoid infinite
 * recursion
 * @example
 * ```
 * Path<{foo: {bar: string}}> = 'foo' | 'foo.bar'
 * ```
 */
export type Path<T, TraversedTypes = never> = T extends ReadonlyArray<infer V>
  ? IsTuple<T> extends true
    ? {
        [K in TupleKeys<T>]-?: PathImpl<K & string, T[K], TraversedTypes>;
      }[TupleKeys<T>]
    : PathImpl<ArrayKey, V, TraversedTypes>
  : {
      [K in keyof T]-?: PathImpl<K & string, T[K], TraversedTypes>;
    }[keyof T];

/**

Review comment (refactor):
I think this can be simplified to `V extends Extract<TraversedTypes, V>`.

- `Extract<V, TraversedTypes>` should always be `V` due to the preceding `V extends TraversedTypes`.
- `V` also can't be a union due to the preceding `V extends TraversedTypes`. Wrapping it in a tuple should be unnecessary.

Can you please add a comment why this conditional is required? I.e. to make sure that `V` is actually part of `TraversedTypes` and not only a subtype of any of the types in `TraversedTypes`.

Maybe this should be extracted as its own type? See `IsAny` or `isNever` in [`types/utils.ts`](https://github.com/react-hook-form/react-hook-form/blob/master/src/types/utils.ts)

Code after:
import { FieldValues } from '../fields';
import {
  BrowserNativeObject,
  IsAny,
  IsEqual,
  Primitive,
  UnPackAsyncDefaultValues,
} from '../utils';

import { ArrayKey, IsTuple, TupleKeys } from './common';

/**
 * Helper function to break apart T1 and check if any are equal to T2
 *
 * See {@link IsEqual}
 */
type AnyIsEqual<T1, T2> = T1 extends T2
  ? IsEqual<T1, T2> extends true
    ? true
    : never
  : never;

/**
 * Helper type for recursively constructing paths through a type.
 * This actually constructs the strings and recurses into nested
 * object types.
 *
 * See {@link Path}
 */
type PathImpl<K extends string | number, V, TraversedTypes> = V extends
  | Primitive
  | BrowserNativeObject
  ? `${K}`
  : // Check so that we don't recurse into the same type
  // by ensuring that the types are mutually assignable
  // mutually required to avoid false positives of subtypes
  true extends AnyIsEqual<TraversedTypes, V>
  ? `${K}`
  : `${K}` | `${K}.${PathInternal<V, TraversedTypes | V>}`;

/**
 * Helper type for recursively constructing paths through a type.
 * This obsucres the internal type param TraversedTypes from exported contract.
 *