2

Within our project, we are using the library apollo-angular. This library comes with predefined generic classes. One of these classes is called Query and takes two type parameters. These are its default values Query<T = {}, V = EmptyObject>.

API generator uses these classes to generate an API communication layer, one of these classes looks like this.

class GetPageTypesGQL extends Query<GetPageTypesQuery, GetPageTypesQueryVariables>

export type GetPageTypesQueryVariables = Exact<{ [key: string]: never }>;

export type GetPageTypesQuery = { __typename?: 'Query'; feedPageTypes: Array<string> };

export type Exact<T extends { [key: string]: unknown }> = { [K in keyof T]: T[K] };

In our app we had this type for a very long time, its purpose was simple. You provided a class that implemented the Query class and returned its first parameter type. And it looked like this.

export type QueryType<T> = T extends Query<infer Q, infer V> ? Q : never;

So for example you could use it like this.

type GetPageType = QueryType<GetPageTypesGQL> // and the type was GetPageTypesQuery

Unfortunately, this stopped working with the latest Typescript version 4.9.5. Currently, there is some kind of matching which compares Query<T = {}, V = EmptyObject> with Query<GetPageTypesQuery, GetPageTypesQueryVariables> and it results in a falsy value so the return type is always never.

All I came up with until now is

type QueryType<T, Q = any, V = any> = T extends Query<Q, V> ? Q : never;

but it always returns any type or never types, but never extracts the actual type of the first type parameter.

My question to you is, have you experienced something similar or have an idea what might be wrong here? Thank you!

  • With empty classes for GetPageTypesQuery etc. your code works fine for me on Typescript 4.9.5 as well as 4.9.4 in a completely new Angular project. Any chance you could provide a minimal working example? Maybe there is some issue with the type inference? If you do not already have, try turning on strict mode in your tsconfig, maybe this will help you along. PS: https://github.com/microsoft/TypeScript/releases Does not state anything about types in 4.9.5. Which version did you use before? – Loop Feb 09 '23 at 19:05
  • Please, could you post the definition of `GetPageTypesQuery` and `GetPageTypesQueryVariables`? – carlosV2 Feb 14 '23 at 14:18
  • @carlosV2 added to the examples – Pavel Pazderník Feb 15 '23 at 13:44
  • Do you also get `never` if you try to access this type parameter from the `fetch` method? F.e.: `type QueryType> = ReturnType extends Observable> ? R : never;` – carlosV2 Feb 15 '23 at 15:05

1 Answers1

0

It's possible that the change in TypeScript version 4.9.5 has affected the behaviour of your QueryType type alias. The issue may be related to how TypeScript resolves conditional types, which can be a bit tricky.

Here's a possible solution that should work for your use case:

type QueryType<T> = T extends Query<infer Q, any> ? Q : never;

The key difference is that instead of using two type parameters (Q and V), we're only using Q, and we're using infer to extract the type parameter from the Query class.

In this case, we're not concerned with the second type parameter V, so we can just use any as its default value. This should work as long as the Query class always has the same structure, regardless of the type parameters used.

Lewis
  • 1,945
  • 5
  • 26
  • 52