TypeScript
TypeScript copied to clipboard
Calling recursively Generic<infer T>, the T becomes any
Bug Report
Please refer to the playground, I am not able to explain the issue very much. Possibly that when calling a type recursively, which has infered generic param type, than the infered type becomes any
at 2 levels deep.
🔎 Search Terms
- typescript recursive infered generic param is any
- typescript infer results to any
- typescript generic infer any
- type inference changes nested mapped types issue
🕗 Version & Regression Information
Since version 4.8.x
- This changed between versions 4.7 and 4.8
⏯ Playground Link
Playground link with relevant code
This issue arrises in react-navigation (issue) I extracted the relevant code and removed unnecessary parts.
I don't understand the need for the union in the NavigatorScreenParams type, but it is necessary in order for it to work correctly.
I tried simplifying it even more by removing the dependency on NavigatorScreenParams, but the level1
always resolved to any
, therefore I think it's a bug and not a wrong type definition.
💻 Code
// helpers
type NavigatorScreenParams<ParamList> = {
screen?: never;
params?: never;
} | {
[RouteName in keyof ParamList]: {
screen: RouteName;
params: ParamList[RouteName];
};
}[keyof ParamList];
type PathConfig<ParamList extends {}> = {
screens?: PathConfigMap<ParamList>
initialRouteName?: keyof ParamList
}
type PathConfigMap<ParamList extends {}> = {
[RouteName in keyof ParamList]?: NonNullable<ParamList[RouteName]> extends NavigatorScreenParams<infer T extends {}> ? string | PathConfig<T> : string | Omit<PathConfig<{}>, 'screens' | 'initialRouteName'>;
};
// usage
type RootNav = {
root: NavigatorScreenParams<{
level1: NavigatorScreenParams<{
level2: {
someOption: string
}
}>
}>
}
const navConfig: PathConfigMap<RootNav> = {
root: {
initialRouteName: 'level1',
screens: {
level1: {
initialRouteName: 'level2',
screens: {
level2: {
//
},
},
},
},
},
}
🙁 Actual behavior
From the playground, with TS 4.8.4 and above which has the result as:
🙂 Expected behavior
From the playground, with TS 4.7.4 which has the correct result as: