Skip to content

Generic parameters info is not inferred in conditional types over ancestor #55146

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

Closed
typeofweb opened this issue Jul 25, 2023 · 8 comments
Closed
Labels
Not a Defect This behavior is one of several equally-correct options

Comments

@typeofweb
Copy link

Bug Report

In conditional type over an interface X, infer seems not to work for generic parameters when applied to interface Y extends X.

🔎 Search Terms

generic, infer, conditional, interface, extends

🕗 Version & Regression Information

It occurs in all tested versions – including latest, nightly, and some older ones.

⏯ Playground Link

Playground link with relevant code

💻 Code

export interface DocumentTypeDecoration<TResult, TVariables> {}
export interface TypedDocumentNode<TResult, TVariables> extends DocumentTypeDecoration<TResult, TVariables> {}

declare const foo: TypedDocumentNode<{foo: string}, {bar: string}>;

export type ResultOf1<T> = T extends DocumentTypeDecoration<infer ResultType, infer VariablesType>
  ? ResultType
  : never;
export type ResultOf2<T> = T extends TypedDocumentNode<infer ResultType, infer VariablesType>
  ? ResultType
  : never;


type Result1 = ResultOf1<typeof foo>; // unknown, expected to be {foo: string}
type Result2 = ResultOf2<typeof foo>; // got {foo: string} as expected

🙁 Actual behavior

Got unknown.

🙂 Expected behavior

Expected to get {foo: string}.

@MartinJohns
Copy link
Contributor

MartinJohns commented Jul 25, 2023

Because you have unused type parameters.

Why doesn't type inference work on this interface: interface Foo<T> { }?

Remember: You should never have unused type parameters!

See also this comment.

@typeofweb
Copy link
Author

Yes, but it does work for Result2. What's the difference?

@MartinJohns
Copy link
Contributor

And it will work for Result1 when you use DocumentTypeDecoration directly. I don't know the details of how the inference algorithm works, but there's no guarantee anything meaningful is resolved when you don't use the parameters. Once you actually use them it will resolve correctly:

export interface DocumentTypeDecoration<TResult, TVariables> { r: TResult; v: TVariables }

@typeofweb
Copy link
Author

Yes, thank you, that's my question. Why does it allow inferring over unused type parameters in this case but doesn't in another one.

@MartinJohns
Copy link
Contributor

That I don't know. Like I said, I don't know the implementation details of the compilers algorithms in detail. It's probably just an edge case where the type parameter can be taken directly from the declared type, instead of having to actually perform an inference by navigating the type backwards. Maybe someone else can chime in, but generally this repository is not meant for questions.

All I can say is that it's working as intended. This issue is basically the same and closed as Working as Intended. Or this issue.

@Andarist
Copy link
Contributor

Andarist commented Jul 25, 2023

Why does it allow inferring over unused type parameters in this case but doesn't in another one.

it's because foo is typed using TypedDocumentNode and ResultOf2 matches that type alias specifically. So this one is just inferring between those type parameters directly. With ResultOf1 TS infers between contained structures and since your type parameters are unused they don't appear in any position that could act as an inference source.

@RyanCavanaugh
Copy link
Member

To add to @Andarist 's answer: generic inference can take a "shortcut" when relating T<X> to T<Y>, but can't do that for relating T<X> to U<Y> (even if U has extends clauses, doing this wouldn't be safe in the general case).

@RyanCavanaugh RyanCavanaugh added the Not a Defect This behavior is one of several equally-correct options label Jul 25, 2023
@typescript-bot
Copy link
Collaborator

This issue has been marked as "Not a Defect" and has seen no recent activity. It has been automatically closed for house-keeping purposes.

@typescript-bot typescript-bot closed this as not planned Won't fix, can't repro, duplicate, stale Jul 28, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Not a Defect This behavior is one of several equally-correct options
Projects
None yet
Development

No branches or pull requests

5 participants