GeezerVison is showing github.com — Infer operator returning container type instead of applied generic · Issue #48772 · microsoft/TypeScript
Infer operator returning container type instead of applied generic #48772DescriptionBug Report
🔎 Search Terms
infer, conditional type, generic, alias
🕗 Version & Regression Information
- This changed between versions v4.1.5 and v4.2.3
⏯ Playground Link
Playground link with relevant code
💻 Code
type BaseContext<TConfig> = {
foo: number;
config: TConfig;
};
type FullContext<TConfig, TContext> = TContext & BaseContext<TConfig>;
type ExtractAdditionalContext<TContext extends FullContext<any, any>> =
TContext extends FullContext<any, infer TAdditionalContext>
? TAdditionalContext
: never;
type Config = Record<string, string>;
type AdditionalContext = { customValue: string };
type Context = FullContext<Config, AdditionalContext>;
type ExtractedAdditionalContext = ExtractAdditionalContext<Context>;
declare const additionalContext: AdditionalContext;
const test1: ExtractedAdditionalContext = additionalContext;
🙁 Actual behavior
I expected ExtractedAdditionalContext to be AdditionalContext or { customValue: string }, and for test1 to compile without error.
🙂 Expected behavior
ExtractedAdditionalContext is AdditionalContext & BaseContext<Config> which is the same type as Context. test1 results in a compiler error of:
Type 'AdditionalContext' is not assignable to type 'AdditionalContext & BaseContext<Config>'.
Type 'AdditionalContext' is missing the following properties from type 'BaseContext<Config>': foo, config
Additional notes
When I remove the config property from BaseContext the issue is resolved. ActivityRyanCavanaugh commented on Apr 19, 2022 RyanCavanaugh commented on Apr 19, 2022 If you keep substituting in the expansions of each type and see the operation being performed, this is a correct inference -- as in many cases, there are multiple equally correct inferences that can be made, and as a result of the linked PR we switched from a certain correct inference to a different correct inference. In general it's not safe to assume that inferring onto a T & U will reliably "break apart" a source type which was also constructed through a T & U - this can happen, but is not guaranteed to. kschat commented on Apr 19, 2022 Thanks for the quick reply! I can appreciate how this is a correct inference, but it's certainly surprising. I'm sure a case exists, but I'm having a hard time imaging a time where I'd want the current result.
I guess it's partially surprising because I wrote FullContext<any, infer TAdditionalContext>, not infer TContext & BaseContext<any>. The syntax suggests that I'm asking the compiler to tell me what was provided to the second generic of the type. Clearly that's not how the infer keyword works, but that begs the question -- can we have that feature? :) fatcerberus commented on Apr 20, 2022
The syntax suggests that I'm asking the compiler to tell me what was provided to the second generic of the type.
Yeah, inference is structural, not nominal, so the type system is always working backwards from the output of the generic to figure out what should go in the infer position. It's a bit like solving for x in f(x, y) = z given fixed y and z - the solution isn't guaranteed to be unique, depending on what f does with its arguments.
Clearly that's not how the infer keyword works, but that begs the question -- can we have that feature? :)
I'm not a TypeScript team member, but from what I do know about how the type system works I'm going to say probably not - in many cases the compiler doesn't even know which type alias a type came from, so infer always has to be done structurally. Reacted by Ryan Cavanaugh and Kyle Schattler RyanCavanaugh commented on Apr 20, 2022 Nothing's impossible but in general we're not keen to spend time tweaking things in the grey areas of inference - there are always going to be cases where there's a structural inference going on here, so making 6 out of 10 cases work as opposed to 4 out of 10 cases doesn't really change the situation much. kschat commented on Apr 21, 2022
Yeah, inference is structural, not nominal, so the type system is always working backwards from the output of the generic to figure out what should go in the infer position. It's a bit like solving for x in f(x, y) = z given fixed y and z - the solution isn't guaranteed to be unique, depending on what f does with its arguments.
Thanks, I was missing this context and it explains why this is so difficult.
Nothing's impossible but in general we're not keen to spend time tweaking things in the grey areas of inference
That's reasonable and I understand why the team takes that position. I'll close this issue, thanks for you time. kschat commented on Apr 21, 2022 Dave Campion (@dpchamps) came up with a good solution to my problem that I'll post here for others. Instead of inferring the generic, we can omit the keys in BaseContext from FullContext. This can omit too much if AdditionalContext contains keys that are also in BaseContext, but that's not a problem in my case. Here's a working example. locked as resolved and limited conversation to collaborators on Oct 22, 2025
MetadataMetadataDevelopmentNo branches or pull requestsIssue actions
|