redwoodjs / redwood

The App Framework for Startups
https://redwoodjs.com
MIT License
17.27k stars 991 forks source link

[Dependency Bug?]: V6.5.0 type-check on API side causing memory issues with types that can recurse #9650

Open cjreimer opened 10 months ago

cjreimer commented 10 months ago

What's not working?

Summary

Posted as an troubleshooting FYI for anyone else that could run into this...

As Redwood v6.5.0 now upgrades typescript to v5.3.2, the latest typescript releases appear to be susceptible to memory errors on types that can recurse infinitely. The key to solving these issues is to run: yarn tsc --noEmit --extendedDiagnostics from the api or web side folder as appropriate.

This identified where the issues were in code.

From an architecture point of things, we got into this scenario when we had child graphQL types that referenced the parent. For example:

export const schema = gql`
  type Issue {
    id: Int!
    actions: [IssueAction]
   ...
  }

export const schema = gql`
  type IssueAction {
    id: Int!
    issue: Issue!  # this was the root of the problem (along with some custom types we had to help resolvers)
  }
`

Details

We had memory heap limit issues when running Redwood 6.5.0. No issues were encountered on previous releases up to v6.4.2. We understand that typescript was upgraded to v5.3.2 in Redwood v6.5.0. We tried forcing a resolution to typescript patch v5.3.3, which is now out, with no change. We see the following error:

yarn rw type-check api
✔ Generating the Prisma client...
✔ Generating types

<--- Last few GCs --->

[41720:000001B7D4498720]    87931 ms: Scavenge 4044.0 (4124.4) -> 4038.4 (4141.1) MB, 9.1 / 0.0 ms  (average mu = 0.908, current mu = 0.795) allocation failure;
[41720:000001B7D4498720]    89258 ms: Mark-sweep 4053.1 (4141.1) -> 4039.6 (4144.4) MB, 1297.5 / 0.0 ms  (average mu = 0.786, current mu = 0.211) allocation failure; scavenge might not succeed

<--- JS stacktrace --->

FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory
 1: 00007FF6082007BF node_api_throw_syntax_error+175823
 2: 00007FF608185796 DSA_meth_get_flags+59654
 3: 00007FF608187480 DSA_meth_get_flags+67056
 4: 00007FF608C2DCC4 v8::Isolate::ReportExternalAllocationLimitReached+116
 5: 00007FF608C19052 v8::Isolate::Exit+674
 6: 00007FF608A9AF0C v8::internal::EmbedderStackStateScope::ExplicitScopeForTesting+124
 7: 00007FF608A9812B v8::internal::Heap::CollectGarbage+3963
 8: 00007FF608AAE363 v8::internal::HeapAllocator::AllocateRawWithLightRetrySlowPath+2099
 9: 00007FF608AAEC0D v8::internal::HeapAllocator::AllocateRawWithRetryOrFailSlowPath+93
10: 00007FF608ABE3D0 v8::internal::Factory::NewFillerObject+816
11: 00007FF6087AF315 v8::internal::DateCache::Weekday+1349
12: 00007FF608CCB1F1 v8::internal::SetupIsolateDelegate::SetupHeap+558193
13: 00007FF5D16CD590

Note that yarn rw g types works fine. However, yarn tsc --skipLibCheck from the apifolder failed in the same way.

Note that the previous redwood version had typescript pinned to typescript: 5.2.2.

This was looking like a problem in typescript v5.3.x that was specific to our codebase.

What became interesting wasthe result we get when we ran the following:

PS C:\CENRIZE\cengys-r\api> yarn tsc --noEmit --extendedDiagnostics
../.redwood/types/includes/api-globalContext.d.ts:7:9 - error TS2451: Cannot redeclare block-scoped variable 'context'.

7   const context: GlobalContext
          ~~~~~~~

  ../node_modules/@redwoodjs/graphql-server/dist/global.api-auto-imports.d.ts:5:11
    5     const context: GlobalContext;
                ~~~~~~~
    'context' was also declared here.

../.redwood/types/includes/api-globImports.d.ts:2:16 - error TS5061: Pattern 'src/services/**/*.{js,ts}' can have at most one '*' character.

2 declare module 'src/services/**/*.{js,ts}'
                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~

../.redwood/types/includes/api-globImports.d.ts:3:16 - error TS5061: Pattern 'src/directives/**/*.{js,ts}' can have at most one '*' character.

3 declare module 'src/directives/**/*.{js,ts}'
                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

../.redwood/types/includes/api-globImports.d.ts:4:16 - error TS5061: Pattern 'src/graphql/**/*.sdl.{js,ts}' can have at most one '*' 
character.

4 declare module 'src/graphql/**/*.sdl.{js,ts}'
                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

../.redwood/types/includes/api-globImports.d.ts:5:16 - error TS5061: Pattern 'src/subscriptions/**/*.{js,ts}' can have at most one '*' character.

5 declare module 'src/subscriptions/**/*.{js,ts}'
                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

../.redwood/types/mirror/api/src/lib/csv/index.d.ts:2:10 - error TS2305: Module '"./csv"' has no exported member 'default'.

2 import { default as DEFAULT } from './csv'
           ~~~~~~~

../.redwood/types/mirror/api/src/lib/docX/index.d.ts:2:10 - error TS2305: Module '"./docX"' has no exported member 'default'.        

2 import { default as DEFAULT } from './docX'
           ~~~~~~~

../.redwood/types/mirror/api/src/services/checklists/index.d.ts:2:10 - error TS2305: Module '"./checklists"' has no exported member 'default'.

2 import { default as DEFAULT } from './checklists'
           ~~~~~~~

../.redwood/types/mirror/api/src/services/documents/index.d.ts:2:10 - error TS2305: Module '"./documents"' has no exported member 'default'.

2 import { default as DEFAULT } from './documents'
           ~~~~~~~

../.redwood/types/mirror/api/src/services/equipTypeLogs/index.d.ts:2:10 - error TS2305: Module '"./equipTypeLogs"' has no exported member 'default'.

2 import { default as DEFAULT } from './equipTypeLogs'
           ~~~~~~~

../.redwood/types/mirror/api/src/services/events/index.d.ts:2:10 - error TS2305: Module '"./events"' has no exported member 'default'.

2 import { default as DEFAULT } from './events'
           ~~~~~~~

../.redwood/types/mirror/api/src/services/issueAtt/index.d.ts:2:10 - error TS2305: Module '"./issueAtt"' has no exported member 'default'.

2 import { default as DEFAULT } from './issueAtt'
           ~~~~~~~

../.redwood/types/mirror/api/src/services/issueFollows/index.d.ts:2:10 - error TS2305: Module '"./issueFollows"' has no exported member 'default'.

2 import { default as DEFAULT } from './issueFollows'
           ~~~~~~~

../.redwood/types/mirror/api/src/services/opRequests/index.d.ts:2:10 - error TS2305: Module '"./opRequests"' has no exported member 'default'.

2 import { default as DEFAULT } from './opRequests'
           ~~~~~~~

../.redwood/types/mirror/api/src/services/reqActions/index.d.ts:2:10 - error TS2305: Module '"./reqActions"' has no exported member 'default'.

2 import { default as DEFAULT } from './reqActions'
           ~~~~~~~

../.redwood/types/mirror/api/src/services/requirements/index.d.ts:2:10 - error TS2305: Module '"./requirements"' has no exported member 'default'.

2 import { default as DEFAULT } from './requirements'
           ~~~~~~~

../.redwood/types/mirror/api/src/services/submittalReviewDisclaimers/index.d.ts:2:10 - error TS2305: Module '"./submittalReviewDisclaimers"' has no exported member 'default'.

2 import { default as DEFAULT } from './submittalReviewDisclaimers'
           ~~~~~~~

../.redwood/types/mirror/api/src/services/submittalReviewResults/index.d.ts:2:10 - error TS2305: Module '"./submittalReviewResults"' 
has no exported member 'default'.

2 import { default as DEFAULT } from './submittalReviewResults'
           ~~~~~~~

../.redwood/types/mirror/api/src/services/submittals/index.d.ts:2:10 - error TS2305: Module '"./submittals"' has no exported member 'default'.

2 import { default as DEFAULT } from './submittals'
           ~~~~~~~

../.redwood/types/mirror/api/src/services/users/index.d.ts:2:10 - error TS2305: Module '"./users"' has no exported member 'default'. 

2 import { default as DEFAULT } from './users'
           ~~~~~~~

src/services/issueFollows/issueFollows.ts:455:33 - error TS2589: Type instantiation is excessively deep and possibly infinite.       

455     if ('issue' in root) return root.issue as ResolversTypes['Issue']
                                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

../node_modules/@redwoodjs/graphql-server/dist/createGraphQLYoga.d.ts:3:11 - error TS2304: Cannot find name 'ServerAdapter'.

3     yoga: ServerAdapter<TServerContext, import("graphql-yoga").YogaServer<TServerContext, TUserContext>>;
            ~~~~~~~~~~~~~

../node_modules/@redwoodjs/graphql-server/dist/createGraphQLYoga.d.ts:3:25 - error TS2304: Cannot find name 'TServerContext'.        

3     yoga: ServerAdapter<TServerContext, import("graphql-yoga").YogaServer<TServerContext, TUserContext>>;
                          ~~~~~~~~~~~~~~

../node_modules/@redwoodjs/graphql-server/dist/createGraphQLYoga.d.ts:3:75 - error TS2304: Cannot find name 'TServerContext'.        

3     yoga: ServerAdapter<TServerContext, import("graphql-yoga").YogaServer<TServerContext, TUserContext>>;
                                                                            ~~~~~~~~~~~~~~

../node_modules/@redwoodjs/graphql-server/dist/createGraphQLYoga.d.ts:3:91 - error TS2304: Cannot find name 'TUserContext'.

3     yoga: ServerAdapter<TServerContext, import("graphql-yoga").YogaServer<TServerContext, TUserContext>>;
                                                                                            ~~~~~~~~~~~~

../node_modules/@redwoodjs/graphql-server/dist/global.api-auto-imports.d.ts:5:11 - error TS2451: Cannot redeclare block-scoped variable 'context'.

5     const context: GlobalContext;
            ~~~~~~~

  ../.redwood/types/includes/api-globalContext.d.ts:7:9
    7   const context: GlobalContext
              ~~~~~~~
    'context' was also declared here.

../node_modules/@redwoodjs/graphql-server/dist/types.d.ts:9:45 - error TS2307: Cannot find module '@redwoodjs/realtime' or its corresponding type declarations.

9 import type { RedwoodRealtimeOptions } from '@redwoodjs/realtime';
                                              ~~~~~~~~~~~~~~~~~~~~~

../node_modules/@redwoodjs/graphql-server/dist/types.d.ts:10:43 - error TS2307: Cannot find module 'src/directives/makeDirectives' or its corresponding type declarations.

10 import type { DirectiveGlobImports } from 'src/directives/makeDirectives';
                                             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Found 28 errors in 21 files.

Errors  Files
     1  ../.redwood/types/includes/api-globalContext.d.ts:7
     4  ../.redwood/types/includes/api-globImports.d.ts:2
     1  ../.redwood/types/mirror/api/src/lib/csv/index.d.ts:2
     1  ../.redwood/types/mirror/api/src/lib/docX/index.d.ts:2
     1  ../.redwood/types/mirror/api/src/services/checklists/index.d.ts:2
     1  ../.redwood/types/mirror/api/src/services/documents/index.d.ts:2
     1  ../.redwood/types/mirror/api/src/services/equipTypeLogs/index.d.ts:2
     1  ../.redwood/types/mirror/api/src/services/events/index.d.ts:2
     1  ../.redwood/types/mirror/api/src/services/issueAtt/index.d.ts:2
     1  ../.redwood/types/mirror/api/src/services/issueFollows/index.d.ts:2
     1  ../.redwood/types/mirror/api/src/services/opRequests/index.d.ts:2
     1  ../.redwood/types/mirror/api/src/services/reqActions/index.d.ts:2
     1  ../.redwood/types/mirror/api/src/services/requirements/index.d.ts:2
     1  ../.redwood/types/mirror/api/src/services/submittalReviewDisclaimers/index.d.ts:2
     1  ../.redwood/types/mirror/api/src/services/submittalReviewResults/index.d.ts:2
     1  ../.redwood/types/mirror/api/src/services/submittals/index.d.ts:2
     1  ../.redwood/types/mirror/api/src/services/users/index.d.ts:2
     1  src/services/issueFollows/issueFollows.ts:455
     4  ../node_modules/@redwoodjs/graphql-server/dist/createGraphQLYoga.d.ts:3
     1  ../node_modules/@redwoodjs/graphql-server/dist/global.api-auto-imports.d.ts:5
     2  ../node_modules/@redwoodjs/graphql-server/dist/types.d.ts:9
Files:                         2379
Lines of Library:             40612
Lines of Definitions:        500064
Lines of TypeScript:         120840
Lines of JavaScript:              0
Lines of JSON:                    0
Lines of Other:                   0
Identifiers:                 820259
Symbols:                    6915673
Types:                      1550290
Instantiations:            29941427
Memory used:               4163154K
Assignability cache size:   1155797
Identity cache size:           3987
Subtype cache size:            8555
Strict subtype cache size:      472
I/O Read time:                0.36s
Parse time:                   1.66s
ResolveModule time:           0.60s
ResolveTypeReference time:    0.02s
ResolveLibrary time:          0.02s
Program time:                 2.90s
Bind time:                    0.92s
Check time:                  89.97s
printTime time:               0.00s
Emit time:                    0.00s
Total time:                  93.78s

I also ran this on the same codebase with the previous redwood version, and had the same errors, minus this one:

src/services/issueFollows/issueFollows.ts:455:33 - error TS2589: Type instantiation is excessively deep and possibly infinite.       

455     if ('issue' in root) return root.issue as ResolversTypes['Issue']

Cleaning up these two resolvers that could recurse solved the issue. The latest version of typescript doesn't seem to handle this case nicely! In the summary, I have provided some insights into how our code got into this scenario.

How do we reproduce the bug?

No response

What's your environment? (If it applies)

yarn rw info

  System:
    OS: Windows 10 10.0.19045
  Binaries:
    Node: 18.19.0 - C:\Users\CURTIS~1\AppData\Local\Temp\xfs-f604011f\node.CMD
    Yarn: 3.6.2 - C:\Users\CURTIS~1\AppData\Local\Temp\xfs-f604011f\yarn.CMD
  Browsers:
    Edge: Spartan (44.19041.3636.0), Chromium (119.0.2151.93)
  npmPackages:
    @redwoodjs/auth-firebase-setup: 6.5.0 => 6.5.0
    @redwoodjs/cli-data-migrate: 6.5.0 => 6.5.0
    @redwoodjs/cli-storybook: 6.5.0 => 6.5.0
    @redwoodjs/core: 6.5.0 => 6.5.0

Are you interested in working on this?

Josh-Walker-GM commented 10 months ago

Thanks for the detailed issue @cjreimer! I'll reproduce this tomorrow locally and have a read through the related issues on the TS repo. Basically the next step here is on me to reproduce. We have been releasing at speed lately so hopefully if TS has a further patch out that fixes this behaviour we'll get it in relatively soon.

cjreimer commented 10 months ago

Thanks @Josh-Walker-GM. Note that we did have some custom types on the resolvers to try to get around the recursive issues. If you are trying to reproduce, then the below might help show what we were doing (with cleanout of non-relevant code). We weren't actually using this feature on the client / web side, so we are planning to blow away the recursive part of this in our graphQL schema. That being said, it's easy enough for someone to get into this case!

//=======================================
// Resolver
//=======================================

type IssueActionRelationResolversModified = Omit<
  IssueActionRelationResolvers,
  'issue'
> & {
  issue: RequiredResolverFn<
    IssueReducedResolverType,
    ResolversParentTypes['IssueAction'],
    RedwoodGraphQLContext
  >
}

export const IssueAction: IssueActionRelationResolversModified = {
  issue: (_obj, { root }) => {
    if ('issue' in root) return root.issue as ResolversTypes['Issue']
    return db.issueAction.findUnique({ where: { id: root.id } }).issue()
  },
}

Thanks!

dthyresson commented 10 months ago

Just a bump to assign to @Josh-Walker-GM to follow up.

Josh-Walker-GM commented 10 months ago

Hey @cjreimer, could you clarify IssueReducedResolverType for me? I think it'll help me reproduce this which I haven't yet

cjreimer commented 10 months ago

Josh, I spent a good amount of time looking into this further last night and this morning. I'm pretty sure this is not related to the custom typing we did ... that's another topic. When I removed the custom typing, the issue remains. We have a scenario in our graphQL schema that can cause typescript to try to analyze type instantiation that is excessively and possibly infinite. See the error we get in vscode in the image below.

image

What is interesting is that we do not get this error in yarn rw type-check or when running tsc directly, so it appears that this error is not spit out upon compilation. I'm not sure how long we had this error, but it may have been there a few weeks to a month without us noticing, due to yarn rw type-check not showing it.

There is something quite tricky going on to get into this case, based on when we get this warning. As you know, graphql is well ... a graph or mesh, and our schema interlinks quite a bit with many relation edges. In playing with it, trying to add and remove edges, there appears to be a fairly complex configuration required to generate this error, not just a simple node that points back to its parent node. I think multi-loops are required, but I haven't had the time to figure out the exact pattern that results in this error.

So, it looks like we have a complex scenario in our graphQL schema that causes an infinite type scenario in graphQL-codegen and can break typescript. I think for you or the graphQL-codegen to look at this further, we'll need to map out a minimum graphql schema configuration that can generate this scenario. Leave that with us. As for us, in the moment, we can solve this for the moment by taking out a relation edge or two.

Thanks!

Josh-Walker-GM commented 10 months ago

Thanks again @cjreimer! I agree that it might be helpful to find a schema of sufficient complexity to trigger this. I did try with some basic recursive types but I suspected it wasn't so complex as to reproduce this issue. I'll leave it with you but feel free to ping me again.

cjreimer commented 10 months ago

@Josh-Walker-GM , ok, I spent some time playing with our models, and it's not straight-forward. Here's a graph of some of our models and relations, and the red lines are the relations where if I break any one of them, we no longer get the type instantiation is excessively deep and possibly infinite warning. I didn't check every relation... this already burnt more time than I could really afford.

image

Now that we understand what's going on, this is relatively easy for us to fix for now, as we didn't need all these relations in the graphQL. That being said, I can see how some other decent-sized projects could get into this as well. There is a reasonable amount of discussion on this warning at: https://github.com/i18next/react-i18next/issues?q=is%3Aissue+Type+instantiation+is+excessively+deep+and+possibly+infinite

I'm not sure how helpful this is for you, but it reinforces that we only get into this situation with a reasonably complex recursion scenario that has some depth to it.

As for recommendations for the redwood team, it would be very helpful, at minimum, if we could get the redwood yarn rw type-check command to spit out an error or warning on ts 2589. The fact we could only see this warning via IntelliSense made this whole scenario a head-scratcher for a while.

Thanks!

Josh-Walker-GM commented 9 months ago

@cjreimer Thanks. I'll bring up enhancing yarn rw type-check with the team and get thoughts on it - seems reasonable to me. I'll follow up with a PR in that case or get back to you here if there are other ideas.

larsvaehrens commented 2 months ago

I just stumbled upon this exact issue. We ran into the same IntelliSense errors with type instantiation is excessively deep and possibly infinite some time ago, but didn't dig into it at the time. Now when trying to set up a CI workflow with yarn rw type-check api we get the out-of-memory issue too:

heap out of memory ```sh <--- Last few GCs ---> [459080:0x6cbda20] 42013 ms: Mark-Compact (reduce) 2045.4 (2081.9) -> 2044.9 (2081.9) MB, 11.30 / 0.00 ms (+ 369.5 ms in 82 steps since start of marking, biggest step 7.1 ms, walltime since start of marking 441 ms) (average mu = 0.329, current mu = 0.[459080:0x6cbda20] 42019 ms: Scavenge 2045.9 (2081.9) -> 2045.0 (2084.9) MB, 2.98 / 0.00 ms (average mu = 0.329, current mu = 0.313) allocation failure; <--- JS stacktrace ---> FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory ----- Native stack trace ----- 1: 0xb82d33 node::OOMErrorHandler(char const*, v8::OOMDetails const&) [/home/lars/.local/share/mise/installs/node/20.16.0/bin/node] 2: 0xef0c50 v8::Utils::ReportOOMFailure(v8::internal::Isolate*, char const*, v8::OOMDetails const&) [/home/lars/.local/share/mise/installs/node/20.16.0/bin/node] 3: 0xef0f37 v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, v8::OOMDetails const&) [/home/lars/.local/share/mise/installs/node/20.16.0/bin/node] 4: 0x1102ad5 [/home/lars/.local/share/mise/installs/node/20.16.0/bin/node] 5: 0x1103064 v8::internal::Heap::RecomputeLimits(v8::internal::GarbageCollector) [/home/lars/.local/share/mise/installs/node/20.16.0/bin/node] 6: 0x1119f54 v8::internal::Heap::PerformGarbageCollection(v8::internal::GarbageCollector, v8::internal::GarbageCollectionReason, char const*) [/home/lars/.local/share/mise/installs/node/20.16.0/bin/node] 7: 0x111a76c v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, v8::internal::GarbageCollectionReason, v8::GCCallbackFlags) [/home/lars/.local/share/mise/installs/node/20.16.0/bin/node] 8: 0x10f0a71 v8::internal::HeapAllocator::AllocateRawWithLightRetrySlowPath(int, v8::internal::AllocationType, v8::internal::AllocationOrigin, v8::internal::AllocationAlignment) [/home/lars/.local/share/mise/installs/node/20.16.0/bin/node] 9: 0x10f1c05 v8::internal::HeapAllocator::AllocateRawWithRetryOrFailSlowPath(int, v8::internal::AllocationType, v8::internal::AllocationOrigin, v8::internal::AllocationAlignment) [/home/lars/.local/share/mise/installs/node/20.16.0/bin/node] 10: 0x10ce326 v8::internal::Factory::AllocateRaw(int, v8::internal::AllocationType, v8::internal::AllocationAlignment) [/home/lars/.local/share/mise/installs/node/20.16.0/bin/node] 11: 0x10bfa9c v8::internal::FactoryBase::AllocateRawArray(int, v8::internal::AllocationType) [/home/lars/.local/share/mise/installs/node/20.16.0/bin/node] 12: 0x10bfc04 v8::internal::FactoryBase::NewFixedArrayWithFiller(v8::internal::Handle, int, v8::internal::Handle, v8::internal::AllocationType) [/home/lars/.local/share/mise/installs/node/20.16.0/bin/node] 13: 0x13ef9bd v8::internal::OrderedHashTable::Allocate(v8::internal::Isolate*, int, v8::internal::AllocationType) [/home/lars/.local/share/mise/installs/node/20.16.0/bin/node] 14: 0x13efa63 v8::internal::OrderedHashTable::Rehash(v8::internal::Isolate*, v8::internal::Handle, int) [/home/lars/.local/share/mise/installs/node/20.16.0/bin/node] 15: 0x1520673 v8::internal::Runtime_MapGrow(int, unsigned long*, v8::internal::Isolate*) [/home/lars/.local/share/mise/installs/node/20.16.0/bin/node] 16: 0x768751ed9ef6 ```

@cjreimer did you make a workaround for the circular type references? We could disable some of the relation resolvers to fix this issue, but I'd rather not go down that path if there is a better solution.

cjreimer commented 2 months ago

@larsvaehrens in the end we had to move forward on this and I took out some relations in the sdl files that we didn't really need. The mesh structure appears to work for graphQL, but the way the typescript structure is right now, it causes issues if there are too many loops. I spent a bit of time trying to figure out the exact conditions that causes this error, but I found it's quite finicky and complex.

Hope that helps.

larsvaehrens commented 1 month ago

Thank you for the suggested workaround.

I have been trying to figure out which part of our structure was causing issues by removing relations one by one but I got to a point where I could not remove any more relations from the SDLs without causing yarn rw g types to error. So I tried removing all relation resolvers from all service files and this fixed the out-of-memory issue on yarn rw type-check api. This was without changing any SDLs which I wasn't too fond of because that would mean the generated types would not be as expected.