-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Improve inference of Recursive types #52722
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
You could "expand" it with a mapped type like this: type GetRecursiveType<T extends readonly Recursive[]> = {
[K in keyof T]: T[K] extends infer U extends Recursive
? U['id'] | (U['children'] extends infer R extends readonly Recursive[]
? GetRecursiveType<R>
: never)
: never
}[number] |
@whzx5byb thanks for the example, could you please explain why using mapped type is different from conditional type I was trying to do? It seems to me that it should do the same, but it doesn't. type GetRecursiveType<T extends readonly Recursive[]> = T[number] extends infer U extends Recursive ? U['id'] | (U['children'] extends infer R extends Recursive[] ? GetRecursiveType<R> : never) : never |
type GetRecursiveType<T extends readonly Recursive[]> =
T[number] extends infer U extends Recursive
+ ? U extends infer V extends Recursive
- ? U['id'] | (U['children'] extends infer R extends Recursive[]
+ ? V['id'] | (V['children'] extends infer R extends readonly Recursive[]
? GetRecursiveType<R>
: never)
: never
+ : never |
@whzx5byb Thanks for explanation. So the |
Generally correct. A distributive type parameter |
This just seems like a bug. There's not anything super different between the provided example and this variant (which works as expected): type NotRecursive<Id> = {
id: Id
other: Id;
}
function getIds<Id>(items: readonly NotRecursive<Id>[]): Id[] {
return [] // return value is not important
}
const items = [{
id: 'a',
other: 'b'
}] as const satisfies readonly NotRecursive<string>[]
const foo = getIds(items)
// inferred type arg is "a" | "b" |
Suggestion
It would be nice to be able to infer all variants from a recursive type. Playground link.
🔍 Search Terms
recursive types
✅ Viability Checklist
My suggestion meets these guidelines:
It might be breaking from types perspective if some code relies on the current behaviour.
⭐ Suggestion
Generics inside recursive types would be expanded.
📃 Motivating Example
E.g. for selectable nested lists, we could provide auto-complete for
onSelect(itemId: <union of all ids from recursive type>)
.💻 Use Cases
I haven't found a workaround that would work for the
getIds
function in the example. One semi working workaround is written below - it returns correctly union of all ids literals, but TS shows an error and it cannot be used as return value forgetIds(...)
because then TS show that the type is recursive and possible infinite.Playground link.
The text was updated successfully, but these errors were encountered: