This is a typescript question, i will try to explain as good as possible. Find a link to a typescript playground with an illustration of the problem at the bottom.
It is about react-hook-form, which has a type Path<TFieldValues> (see https://github.com/react-hook-form/react-hook-form/blob/274d8fb950f9944547921849fb6b3ee6e879e358/src/types/utils.ts#L86), which is a string identifier for a possible nested field in dot-notation (i.e. path, path.subpath, path.subpath.subpath etc.) for a given structure TFieldValues, which are the form values. Its hooks require this Path<TFieldValues> when specifying a fieldName, which is desired and nice.
But i have a problem deriving such a Path<TFieldValues> variable, when i have a structure definition which i recursively iterate. What i am doing is, to traverse a structure definition (that conforms to the TFieldValues structure) with information on the ui. Then i traverse it and generate the UI for that, using useController. However i cannot find a way to have a strongly typed Path<TFieldValues>. You can see in the complete example in the link below, the gist:
// Simplified from react-hook-form, we only care about fieldName typing
const useController = <TFieldValues extends Record<string, any>>(fieldName: Path<TFieldValues>) => {};
// Could be something arbitrary but a fixed structure is given
const myValues = {
    number: 1,
    string: 'string',
    sub: {
        number: 2,
        sub: {
            string: 'string',
        },
    },
};
// This schema will be recursively walked to generate a UI, it is strongly typed to conform to myValues but that would exceed this post
const schema = {
    number: 'Number Field',
    string: 'String Field',
    sub: {
        number: 'Sub Number Field',
        sub: {
            string: 'Sub Sub String Field',
        },
    },
};
// This walk function illustrates the problem, as i cannot determine how to derive a valid path when recursive iterating
const walk = (node: Record<string, any>, path?: Path<typeof myValues>) => {
    const keys = Object.keys(node);
    for (let key in keys) {
        if (typeof node[key] === 'string') {
            useController<typeof myValues>(path ? `${path}.${key}` : key);
            // Show UI etc...
        } else {
            walk(node[key], path ? `${path}.${key}` : key);
        }
    }
}
// would be called
walk(schema);
Here is the problem illustrated in the typescript playground: TS Playground
P.S: Please do not suggest using as, any or something like that. I know i could cast it to make it work. But i want strong typing.
EDIT
A little edit here, as i was doing some more research. I think the problem can be simplified for better understanding. The main point is appending a new key to Path<X> and still get a valid Path<X> in return. If we can solve that, typing the recursive iteration should not be the problem. This essentially can be expressed in a simple function
declare function appendToPath<T>(path: Path<T>, appendKey: ???): Path<T>; 
I tried to improve that, and have at least validly typed function parameters that behave correctly:
// Helper to determine valid keys for a nested object value
type NestedObjectKey<
    T extends FieldPathValue<TFieldValues, TFieldPath>,
    TFieldValues extends FieldValues = FieldValues,
    TFieldPath extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
> = T extends Record<string, any> ? keyof T : never;
// Append
function appendToPath<
    TFieldValues extends FieldValues = FieldValues,
    TFieldPath extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
>(path: TFieldPath, keyToAppend: NestedObjectKey<FieldPathValue<TFieldValues, TFieldPath>>): Path<TFieldValues> {
    return `${path}.${keyToAppend}`; // this still raises an error
}
So from a human standpoint this should be enough logically and works as far using the function and its function signature is concerned. However unfortunately TS cannot infer this information as a human can when assembling the path and i have not found a way to do so so far. Last resort would be a custom type assertion, but that would add unnecessary code.
Another way to look at it from a human standpoint is a ${Path<A>}.${Path<B>} is still a Path<A> variable if FieldValue<A, Path<A>> = B. I don't know if that could be translated to a working typescript implementation