Skip to content
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

Improve error message for users of old TypeScript versions #6423

Closed
glasser opened this issue May 12, 2022 · 6 comments
Closed

Improve error message for users of old TypeScript versions #6423

glasser opened this issue May 12, 2022 · 6 comments
Milestone

Comments

@glasser
Copy link
Member

glasser commented May 12, 2022

We intend to use some brand-new TS 4.7 features (variance annotations) so let's add https://github.com/sandersn/downlevel-dts to the build process so we can have dts files that work with older TypeScript. We can set up the build script now rather than waiting for 4.7 to be out.

@glasser glasser added this to the Release 4.0 milestone May 12, 2022
glasser added a commit that referenced this issue Jul 12, 2022
…gins

This change does two things, which we originally thought were kind of
connected but maybe aren't.

First, we switch the implementation of contravariance from a hacky
`__forceTContextToBeContravariant` field to the new TS 4.7 variance
annotations. But in fact, instead of making it contravariant, we make it
invariant: `ApolloServer<X>` can only be assigned to `ApolloServer<Y>`
when X and Y are the same. This is because:

- An `ApolloServer<{foo: number}>` is not a `ApolloServer<{}>`, because
  you can invoke `executeOperation` on the latter with an empty context
  object, which would confuse the former (this is the contravariance we
  already had).
- An `ApolloServer<{}>` is not a `ApolloServer<{foo: number}>`, because
  you can invoke `addPlugin` on the latter with a plugin whose methods
  expect to be called with a `contextValue` with `{foo: number}` on it,
  which isn't the case for the former.

Considering the second condition is why this is now invariant (`in
out`).  We're not quite sure why TS couldn't figure this out for us, but
it can't.

Second, we add `server: ApolloServer` to various plugin hook arguments
(`GraphQLRequestContext` and `GraphQLServerContext`). This makes
`logger` and `cache` on `GraphQLRequestContext` somewhat redundant, so
we make those fields into public readonly fields on `ApolloServer` and
remove them from the plugin hook arguments. (We thought this was related
to the other part because adding `server` appeared to require invariance
instead of contravariance, but it turns out that we needed invariance
anyway due to `addPlugin`.)

Note that this means that anyone consuming our `.d.ts` files must be on
TS4.7. Before v4.0.0 we'll probably fix that; see #6423.

Fixes #6264. Fixes #6082.
glasser added a commit that referenced this issue Jul 12, 2022
…gins

This change does two things, which we originally thought were kind of
connected but maybe aren't.

First, we switch the implementation of contravariance from a hacky
`__forceTContextToBeContravariant` field to the new TS 4.7 variance
annotations. But in fact, instead of making it contravariant, we make it
invariant: `ApolloServer<X>` can only be assigned to `ApolloServer<Y>`
when X and Y are the same. This is because:

- An `ApolloServer<{foo: number}>` is not a `ApolloServer<{}>`, because
  you can invoke `executeOperation` on the latter with an empty context
  object, which would confuse the former (this is the contravariance we
  already had).
- An `ApolloServer<{}>` is not a `ApolloServer<{foo: number}>`, because
  you can invoke `addPlugin` on the latter with a plugin whose methods
  expect to be called with a `contextValue` with `{foo: number}` on it,
  which isn't the case for the former.

Considering the second condition is why this is now invariant (`in
out`).  We're not quite sure why TS couldn't figure this out for us, but
it can't.

Second, we add `server: ApolloServer` to various plugin hook arguments
(`GraphQLRequestContext` and `GraphQLServerContext`). This makes
`logger` and `cache` on `GraphQLRequestContext` somewhat redundant, so
we make those fields into public readonly fields on `ApolloServer` and
remove them from the plugin hook arguments. (We thought this was related
to the other part because adding `server` appeared to require invariance
instead of contravariance, but it turns out that we needed invariance
anyway due to `addPlugin`.)

Note that this means that anyone consuming our `.d.ts` files must be on
TS4.7. Before v4.0.0 we'll probably fix that; see #6423.

Fixes #6264. Fixes #6082.
glasser added a commit that referenced this issue Jul 12, 2022
…gins (#6668)

This change does two things, which we originally thought were kind of
connected but maybe aren't.

First, we switch the implementation of contravariance from a hacky
`__forceTContextToBeContravariant` field to the new TS 4.7 variance
annotations. But in fact, instead of making it contravariant, we make it
invariant: `ApolloServer<X>` can only be assigned to `ApolloServer<Y>`
when X and Y are the same. This is because:

- An `ApolloServer<{foo: number}>` is not a `ApolloServer<{}>`, because
  you can invoke `executeOperation` on the latter with an empty context
  object, which would confuse the former (this is the contravariance we
  already had).
- An `ApolloServer<{}>` is not a `ApolloServer<{foo: number}>`, because
  you can invoke `addPlugin` on the latter with a plugin whose methods
  expect to be called with a `contextValue` with `{foo: number}` on it,
  which isn't the case for the former.

Considering the second condition is why this is now invariant (`in
out`).  We're not quite sure why TS couldn't figure this out for us, but
it can't.

Second, we add `server: ApolloServer` to various plugin hook arguments
(`GraphQLRequestContext` and `GraphQLServerContext`). This makes
`logger` and `cache` on `GraphQLRequestContext` somewhat redundant, so
we make those fields into public readonly fields on `ApolloServer` and
remove them from the plugin hook arguments. (We thought this was related
to the other part because adding `server` appeared to require invariance
instead of contravariance, but it turns out that we needed invariance
anyway due to `addPlugin`.)

Note that this means that anyone consuming our `.d.ts` files must be on
TS4.7. Before v4.0.0 we'll probably fix that; see #6423.

Fixes #6264. Fixes #6082.
glasser added a commit that referenced this issue Jul 22, 2022
This is an attempt at addressing #6423. However, it sure seems like
`typesVersions` is kinda janky and doesn't work as well as we'd like.
One particular thing I've found is that it doesn't play well with the
`../dist` lines we have in our package.json files, because it only gets
applied if the previously resolved path is under the directory it is in:
https://github.com/microsoft/TypeScript/blob/7b764164ede080afff02ec731dfea72b3f4f73f3/src/compiler/moduleNameResolver.ts#L1942

(Yeah, the typesVersions clauses are not consistent across all of the
files here: I was doing a test that only looked at the top-level and
`/standalone` ones so those are the ones I was iterating on.)

It's possible this is fixable but maybe we should just bump the TS
requirement to v4.7.
@glasser
Copy link
Member Author

glasser commented Jul 22, 2022

This might not be possible; see #6716. We may just need to bump the requirement to v4.7. For now, adding a note requiring v4.7 to the migration guide, but let's reconsider this before the final release (and make sure other parts of the docs show the required version of TS if we do need it to be 4.70.

@IvanGoncharov
Copy link
Member

@glasser Something that can help is making an explicit error for everyone trying to use older TS versions.
Sadly TS decided not to implement this feature, so I implemented a workaround in graphql-js:
https://github.com/graphql/graphql-js/blob/743f42b6ef6006d35bf9e0b45e3b70d6e9100596/resources/build-npm.ts#L86-L97
It produces an error that looks like this:

node_modules/graphql/NotSupportedTSVersion.d.ts:1:63 - error TS1003: Identifier expected.

1 "Package 'graphql' support only TS versions that are >=4.4.0".

@glasser
Copy link
Member Author

glasser commented Aug 15, 2022

That's a good idea. Unfortunately it looks like it depends on the typesVersions feature which is what I had trouble getting to work here... but maybe getting it work in an error-y way is easier than getting it to actually work.

@IvanGoncharov
Copy link
Member

@glasser It should work, since it use an asterisk for the happy path, it shouldn't change TS behavior:
https://github.com/graphql/graphql-js/blob/743f42b6ef6006d35bf9e0b45e3b70d6e9100596/package.json#L7-L13

@glasser glasser changed the title Run downlevel-dts as part of the build process Improve error message for users of old TypeScript versions Aug 30, 2022
@glasser
Copy link
Member Author

glasser commented Sep 27, 2022

post-RC OK

@glasser
Copy link
Member Author

glasser commented Oct 4, 2022

I tried getting this to work with our setup for a bit and didn't make too much progress. TS4.7 has been out for 4+ months at this point anyway.

The sort of error that old TS users will get is:

node_modules/@apollo/server/dist/esm/ApolloServer.d.ts:63:35 - error TS1139: Type parameter declaration expected.

63 export declare class ApolloServer<in out TContext extends BaseContext = BaseContext> {
                                     ~~

Hopefully folks searching for it will find this issue and discover that they need to upgrade to TS4.7 (which is also in the migration guide).

@glasser glasser closed this as completed Oct 4, 2022
@glasser glasser closed this as not planned Won't fix, can't repro, duplicate, stale Oct 4, 2022
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Apr 20, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants