You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Inside a generic function with a remapped type as parameter, elements are wrongfully inferred as {}.Β #63363
typeRenameKeys<HextendsRecord<string,any>>={[Kinstring&keyofHas `on${Capitalize<K>}`]: ()=>void};functionfoo<TextendsRecord<string,any>>(handlers: RenameKeys<T>){for(constnameinhandlers){lethandler: ()=>void=handlers[name]!;// nok// inferred as {}Β instead of () => void;// Type 'NonNullable<RenameKeys<T>[Extract<keyof RenameKeys<T>, string>]>' is not assignable to type '() => void'.// Type '{}' provides no match for the signature '(): void'.(2322)}}
π Actual behavior
The type of the elements of the remapped type is {} inside the generic function.
If we return the element, the returned type is correct (cf playground).
π Expected behavior
The type should be either:
() = void (correct)
unknown or any: TS is unable to properly infer the type.
Having {} is quite strange/surprising.
Additional information about the issue
There is another issue with [K in string&keyof H] which doesn't manifest when we use [K in keyof H] (cf playground):
Note this behavior was introduced after 5.3.3, previously the error was :
Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'RenameKeys<T>'.
No index signature with a parameter of type 'string' was found on type 'RenameKeys<T>'.(7053)
Activity
denis-migdal commentedon Apr 6, 2026
Note this behavior was introduced after 5.3.3, previously the error was :
RyanCavanaugh commentedon Apr 6, 2026
Why are you writing the function signature this way in the first place?
denis-migdal commentedon Apr 6, 2026
This is a minimal reproductible exemple (see below for the real code).
This is a hook system where the hook have names
xxxand the corresponding handler is namedonXxx.The real signature is:
Playground Link
denis-migdal commentedon Apr 7, 2026
For information:
Doesn't solve this specific issue, but seems to cause less inference issues compared to:
I also tested the second issue with:
K in keyof H as K=>(...args: any) => voidK in Extract<keyof H, string>=>(...args: any) => voidK in keyof Pick<H, string>=>(...args: any) => voidK in string&keyof H=>(...args: unknown) => voiddifferentK in keyof H as K extends string ? K : never=>(...args: any) => voidK in keyof H as K & string=>(...args: any) => voidPlayground Link