n1ru4l / envelop

Envelop is a lightweight library allowing developers to easily develop, share, collaborate and extend their GraphQL execution layer. Envelop is the missing GraphQL plugin system.
https://envelop.dev
MIT License
788 stars 127 forks source link

Circular constraint reference in typings/utils.d.ts #1120

Closed Cuel closed 1 year ago

Cuel commented 2 years ago

Describe the bug We are migrating to Envelop and ran into a very odd error when trying to boot up.

node_modules/typescript/lib/lib.es5.d.ts:1553:11 - error TS2313: Type parameter 'P' has a circular constraint.

just for reference, this line is Pick

/**
 * From T, pick a set of properties whose keys are in the union K
 */
type Pick<T, K extends keyof T> = {
    [P in K]: T[P];
};

This was all the output and we began bashing our own code to try and find the error, finally after running tsc --build --verbose we got it to print the origin inside Envelop

node_modules/typescript/lib/lib.es5.d.ts:1553:11 - error TS2313: Type parameter 'P' has a circular constraint.
1553     [P in K]: T[P];
               ~

  node_modules/@envelop/types/utils.d.ts:13:93
    13 export declare type Spread<A extends readonly [...any]> = A extends [infer L, ...infer R] ? SpreadTwo<L, Spread<R>> : {};
                                                                                                   ~~~~~~~~~~~~~~~~~~~~~~~
    Circularity originates in type at this location.

for reference, it's this line with references its own type Spread<A extends readonly [...any]> = A extends [infer L, ...infer R] ? SpreadTwo<L, Spread<R>> : {};

I've tried updating the line to

Spread<A extends readonly [...any]> = A extends [infer L, ...infer R] ? SpreadTwo<L,R> : {};

Which solved the issue on our codebase. Doing the same in envelop repo produces green tests and builds.

I can make a PR with this change but wanted to check first if it should be moved into its own type or what the purpose of it is.

To Reproduce To be fair, I don't know how to reproduce it in Envelop repository, I've tried with --build --verbose and it does not give the same output. My colleague and I get the same error on our different machines with our codebase.

Expected behavior No typings errors

Environment:

Cuel commented 2 years ago

For now we can get around it with skipLibCheck: true in tsconfig.json

dotansimha commented 2 years ago

@Cuel I think this comes for a specific TypeScript setup you have in your project? (and I guess that's why skipLibCheck: true solves that). The reason it's using a circular definition is that we wanted to be able to recursively merge the context type when more than 2 types are used, so we "iterate" the array of types [infer L, ...infer R] and merge the with the previous type.

I wonder why it's not emitting this error in our codebase - do you have a specific tsconfig configuration file that checks that? 🤔

@kamilkisiela thoughts?

Cuel commented 2 years ago

It's a monorepo but our service do not inherit any settings, full tsconfig for the service:

{
  "compilerOptions": {
    "rootDir": "src",
    "esModuleInterop": true,
    "lib": [
      "es2018",
      "es2019",
      "es2020",
    ],
    "module": "commonjs",
    "moduleResolution": "node",
    "outDir": "dist",
    "sourceMap": true,
    "strict": true,
    "strictNullChecks": true,
    "noImplicitAny": true,
    "target": "es2019"
  },
  "include": [
    "**/*.ts"
  ],
  "exclude": [
    "scripts",
    "node_modules"
  ]
}

We import a package that wraps envelop with some default stuff, from what I can tell it doesn't import anything odd and from the typings it's only import type { Plugin } from '@envelop/types'

I've tried building other packages in the repo that all uses their own tsconfig.json and after removing skipLibCheck they all get the same error.

I figured it was to spread altho it doesn't seem to affect anything in this repo but I see it's also an exported type. Could they can be separated to not be circular? Might need some assistance with that

danscan commented 2 years ago

I'm running into this with Deno via GraphQL Yoga @ 2.3.0.

I'm able to work around it by downgrading to GraphQL Yoga @ 2.2.0, but would love to upgrade if this gets fixed. Is #1123 able to be merged?

error: TS2313 [ERROR]: Type parameter 'P' has a circular constraint.
    [P in K]: T[P];
          ^
    at asset:///lib.es5.d.ts:1553:11

TS2751 [ERROR]:     Circularity originates in type at this location.
    export declare type Spread<A extends readonly [...any]> = A extends [infer L, ...infer R] ? SpreadTwo<L, Spread<R>> : {};
                                                                                                ~~~~~~~~~~~~~~~~~~~~~~~
        at https://cdn.skypack.dev/-/@envelop/types@v2.2.0-Q6As234pOCPxxJwEnodu/dist=es2019,mode=types/utils.d.ts:13:93

TS2313 [ERROR]: Type parameter 'P' has a circular constraint.
    [P in K]: T[P];
          ^
    at asset:///lib.es5.d.ts:1553:11

TS2751 [ERROR]:     Circularity originates in type at this location.
    export declare type Spread<A extends readonly [...any]> = A extends [infer L, ...infer R] ? SpreadTwo<L, Spread<R>> : {};
                                                                                                ~~~~~~~~~~~~~~~~~~~~~~~
        at https://cdn.skypack.dev/-/@envelop/types@v2.2.0-Q6As234pOCPxxJwEnodu/dist=es2019,mode=types/utils.d.ts:13:93

TS2313 [ERROR]: Type parameter 'P' has a circular constraint.
    [P in K]: T[P];
          ^
    at asset:///lib.es5.d.ts:1553:11

TS2751 [ERROR]:     Circularity originates in type at this location.
    export declare type Spread<A extends readonly [...any]> = A extends [infer L, ...infer R] ? SpreadTwo<L, Spread<R>> : {};
                                                                                                ~~~~~~~~~~~~~~~~~~~~~~~
        at https://cdn.skypack.dev/-/@envelop/types@v2.2.0-Q6As234pOCPxxJwEnodu/dist=es2019,mode=types/utils.d.ts:13:93

TS2741 [ERROR]: Property '[Symbol.asyncIterator]' is missing in type 'AsyncIterator<R, any, undefined>' but required in type 'AsyncIterableIterator<R>'.
  return res.readable[Symbol.asyncIterator]();
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    at https://deno.land/std@0.136.0/async/pool.ts:67:3

    '[Symbol.asyncIterator]' is declared here.
        [Symbol.asyncIterator](): AsyncIterableIterator<T>;
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        at asset:///lib.es2018.asynciterable.d.ts:44:5

TS2304 [ERROR]: Cannot find name 'WindowOrWorkerGlobalScope'.
    fetch: WindowOrWorkerGlobalScope['fetch'];
           ~~~~~~~~~~~~~~~~~~~~~~~~~
    at https://cdn.skypack.dev/-/@graphql-yoga/common@v2.3.0-aKFNqzlhJVQKRiIziXtt/dist=es2019,mode=types/server.d.ts:102:12

TS2304 [ERROR]: Cannot find name 'WindowOrWorkerGlobalScope'.
    at https://cdn.skypack.dev/-/@graphql-yoga/common@v2.3.0-aKFNqzlhJVQKRiIziXtt/dist=es2019,mode=types/server.d.ts:107:140
dfee commented 2 years ago

I'm getting it, too. While skipLibCheck solves it... it's not ideal.

It's trivial to reproduce using @envelop with @graphql-yoga/node, here's an example: https://github.com/dfee/graphql-yoga-circular

  node_modules/@envelop/types/utils.d.ts:13:93
    13 export declare type Spread<A extends readonly [...any]> = A extends [infer L, ...infer R] ? SpreadTwo<L, Spread<R>> : {};
                                                                                                   ~~~~~~~~~~~~~~~~~~~~~~~
    Circularity originates in type at this location.
kamilkisiela commented 2 years ago

@dfee https://github.com/dfee/graphql-yoga-circular/pull/1

kamilkisiela commented 2 years ago

It works fine in TS 4.1+ and fails on versions prior to 4.1

kamilkisiela commented 2 years ago

if somebody can create a reproduction I would be happy to investigate more, so far it seems like everything works fine.

n1ru4l commented 2 years ago

Closing this as it is fixed in recent TypeScript versions.

n1ru4l commented 1 year ago

@kamilkisiela There is now a reproduction available: