TypeScript: Surprising circularity error in 3.9 RC

I haven’t had a chance to reduce the repro, but people seem eager to get started. I’ll try to update with better steps. For now:

  1. git clone --depth=1 https://github.com/davidkpiano/xstate
  2. yarn install --ignore-scripts
  3. tsc -b -f packages/xstate-vue
  4. Fix packages/core/src/actions.ts:108:9 - error TS2783: 'type' is specified more than once, so this usage will be overwritten.
  5. tsc -b -f packages/xstate-vue

Expected: no errors, as in 3.8.3 Actual:

packages/xstate-vue/src/xstate-machine.ts:16:14 - error TS2615: Type of property 'machine' circularly references itself in mapped type 'RecordPropsDefinition<{ machine: any; options: any; }>'.

 16     machine: {
                 ~
 17       type: Object,
    ~~~~~~~~~~~~~~~~~~~
... 
 19       default: () => ({})
    ~~~~~~~~~~~~~~~~~~~~~~~~~
 20     },
    ~~~~~

packages/xstate-vue/src/xstate-machine.ts:23:23 - error TS2615: Type of property 'options' circularly references itself in mapped type 'RecordPropsDefinition<{ machine: any; options: any; }>'.

23       default: () => ({})
                         ~~

TypeScript Version: 3.9.1-rc

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 5
  • Comments: 20 (13 by maintainers)

Most upvoted comments

Did this go into 3.9.6? I’m still blocked on upgrading to 3.9 due to unexpected circularity errors in 3.9.6 (repro in https://github.com/piotrwitek/utility-types/issues/144). I have no idea if the bug I’m tripping over is actually a TS bug or a utility-types bug.

The change never got accepted into the 3.9 branch: https://github.com/microsoft/TypeScript/pull/38687

@ktsn @HerringtonDarkholme @Kingwl @jackkoppa @blake-newman have any of you been able to give TypeScript 3.9 a try with Vue?

Yup, can confirm that we still see the same issue in 3.9.5. Let us know if we can help with any additional testing

Is this included in 3.9.5? the milestone and release notes suggests that it should, but I still get this errors in 3.9.5.

how to reproduce:

  1. git clone https://github.com/mpawelski/vuejs_ts_3_9_issue.git
  2. cd vuejs_ts_3_9_issue
  3. yarn
  4. npx typescript@3.9.5 doesn’t work
  5. npx typescript@3.8.3 works

We’ll include this in our May Servicing release

Since this is a regression I’m going to label it a bug. As I said above, the issue here is an object literal that is contextually typed by itself. I think we can fix it by not producing a contextual type in cases where resolution of a contextual mapped type property would cause a circularity error.

It seems to be an issue about mapping type and function overload.

I can reproduce the issue in a minimal fashion:

type Func<T> = () => T

type Mapped<T> = {
  [K in keyof T]: Func<T[K]> // error
  // [K in keyof T]: () => T[K] // this compiles
}

declare function reproduce(options: number): void // removing this line also compiles
declare function reproduce<T>(options: Mapped<T>): T


reproduce({
  name:   () => { return 123 } // ERROR
})

reproduce({
  name() { return 123 } // ok
})

reproduce({
  name: function () { return 123 } // ok
})

Curiously, without the type alias Func<T>, the code above compiles. Also, removing the overload also makes the code compile.

Even weirder, changing arrow function to method or plain function also makes it compile.

Playground link for nightly build

https://www.typescriptlang.org/play/index.html?noImplicitThis=false&allowUnreachableCode=true&allowUnusedLabels=true&downlevelIteration=true&noEmitHelpers=true&esModuleInterop=false&declaration=false&target=99&ts=4.0.0-dev.20200504&ssl=22&ssc=3&pln=1&pc=1#code/C4TwDgpgBAYgrgOwMYB4AqA+KBeKAKAShyzQFgAoC0SKAWQEMxIATdLXAbwqigG0BpKAEsEUANYQQAewBmUNAF0AXLESo0AhRm5QA9Lr6CR4ybPnL8RbCU16DwABZCAzlCRSAtmCEAbCM4oAXwoKZggkH3oAJ2gZNWAhKVEYsCipZjgkCDwpMASk5xUEOA8AIwgogiKS8qi7KBiPKQA3EQBzKEcXKB8RaHofZyk3T28-APIwiOjY+MTkiFT0zIg2HLz5wrpGFjYq+RDKchS0jKy8LnIeBHoPCBUeQmIoDgaIYDgo0QBGACYAZigwXIgQIhxOy3Ol2ut2yRFeMQ+Xygf0BwNB4MWpxWFx0NzuKjiyHyoieCPenx+AKBQQIQA

The quick fix here is to add a {} type annotation: default: (): {} => ({}).

Please reopen, the issue still persists on TypeScript 3.9.3. See @jackkoppa repo and bump the TypeScript version to 3.9.3. Circular references are still there so TypeScript 3.9 can’t be currently used on Vue projects.

I think “object ends up contextually typing itself” is actually a pretty common scenario in vue. 😦 I know I’ve debugged many an issue in the past with that exact premise, and I’ve usually made the fix something along the lines of adjusting contextual typing or inference so the object no longer depended upon itself.