Skip to content

TypeError: tsutils.unionConstituents is not a function or its return value is not iterable #880

Description

@andersk

When running xo with TypeScript 6 and pnpm, I get a crash within @typescript-eslint/no-unsafe-member-access linting certain code. (This doesn’t happen with TypeScript 5, and it doesn’t happen with with npm or yarn or bun instead of pnpm.)

Minimal reproduction from an empty directory:

$ echo '{}' > tsconfig.json
$ echo 'class C { [Symbol.dispose]() {} }' > foo.ts
$ pnpm i typescript xo
$ pnpm exec xo
/tmp/test/node_modules/.pnpm/@typescript-eslint+type-utils@8.59.1_eslint@10.2.1_typescript@5.9.3/node_modules/@typescript-eslint/type-utils/dist/typeFlagUtils.js:47
    for (const t of tsutils.unionConstituents(type)) {
                            ^

TypeError: tsutils.unionConstituents is not a function or its return value is not iterable
Occurred while linting /tmp/test/foo.ts:1
Rule: "@typescript-eslint/no-unsafe-member-access"
    at getTypeFlags (/tmp/test/node_modules/.pnpm/@typescript-eslint+type-utils@8.59.1_eslint@10.2.1_typescript@5.9.3/node_modules/@typescript-eslint/type-utils/dist/typeFlagUtils.js:47:29)
    at isTypeFlagSet (/tmp/test/node_modules/.pnpm/@typescript-eslint+type-utils@8.59.1_eslint@10.2.1_typescript@5.9.3/node_modules/@typescript-eslint/type-utils/dist/typeFlagUtils.js:64:19)
    at isTypeAnyType (/tmp/test/node_modules/.pnpm/@typescript-eslint+type-utils@8.59.1_eslint@10.2.1_typescript@5.9.3/node_modules/@typescript-eslint/type-utils/dist/predicates.js:109:43)
    at Object.checkMemberExpression (/tmp/test/node_modules/.pnpm/@typescript-eslint+eslint-plugin@8.59.1_@typescript-eslint+parser@8.59.1_eslint@10.2.1__079476764d07c04dd64ee7ed4dcc25ed/node_modules/@typescript-eslint/eslint-plugin/dist/rules/no-unsafe-member-access.js:117:52)
    at visitor.<computed> (file:///tmp/test/node_modules/.pnpm/@eslint+compat@2.0.5_eslint@10.2.1/node_modules/@eslint/compat/dist/esm/index.js:373:19)
    at ruleErrorHandler (/tmp/test/node_modules/.pnpm/eslint@10.2.1/node_modules/eslint/lib/linter/linter.js:645:33)
    at /tmp/test/node_modules/.pnpm/eslint@10.2.1/node_modules/eslint/lib/linter/source-code-visitor.js:76:46
    at Array.forEach (<anonymous>)
    at SourceCodeVisitor.callSync (/tmp/test/node_modules/.pnpm/eslint@10.2.1/node_modules/eslint/lib/linter/source-code-visitor.js:76:30)
    at /tmp/test/node_modules/.pnpm/eslint@10.2.1/node_modules/eslint/lib/linter/source-code-traverser.js:291:18 {
  ruleId: '@typescript-eslint/no-unsafe-member-access',
  currentNode: <ref *1> {
    type: 'MemberExpression',
    computed: false,
    object: {
      type: 'Identifier',
      decorators: [],
      name: 'Symbol',
      optional: false,
      typeAnnotation: undefined,
      range: [ 11, 17 ],
      loc: { end: { column: 17, line: 1 }, start: { column: 11, line: 1 } },
      parent: [Circular *1]
    },
    optional: false,
    property: {
      type: 'Identifier',
      decorators: [],
      name: 'dispose',
      optional: false,
      typeAnnotation: undefined,
      range: [ 18, 25 ],
      loc: { end: { column: 25, line: 1 }, start: { column: 18, line: 1 } },
      parent: [Circular *1]
    },
    range: [ 11, 25 ],
    loc: { end: { column: 25, line: 1 }, start: { column: 11, line: 1 } },
    parent: <ref *3> {
      type: 'MethodDefinition',
      accessibility: undefined,
      computed: true,
      decorators: [],
      key: [Circular *1],
      kind: 'method',
      optional: false,
      override: false,
      static: false,
      value: <ref *2> {
        type: 'FunctionExpression',
        range: [ 26, 31 ],
        async: false,
        body: {
          type: 'BlockStatement',
          body: [],
          range: [ 29, 31 ],
          loc: { end: [Object], start: [Object] },
          parent: [Circular *2]
        },
        declare: false,
        expression: false,
        generator: false,
        id: null,
        params: [],
        returnType: undefined,
        typeParameters: undefined,
        loc: {
          end: { column: 31, line: 1 },
          start: { column: 26, line: 1 }
        },
        parent: [Circular *3]
      },
      range: [ 10, 31 ],
      loc: { end: { column: 31, line: 1 }, start: { column: 10, line: 1 } },
      parent: <ref *4> {
        type: 'ClassBody',
        range: [ 8, 33 ],
        body: [ [Circular *3] ],
        loc: { end: { column: 33, line: 1 }, start: { column: 8, line: 1 } },
        parent: <ref *5> {
          type: 'ClassDeclaration',
          abstract: false,
          body: [Circular *4],
          declare: false,
          decorators: [],
          id: {
            type: 'Identifier',
            decorators: [],
            name: 'C',
            optional: false,
            typeAnnotation: undefined,
            range: [Array],
            loc: [Object],
            parent: [Circular *5]
          },
          implements: [],
          superClass: null,
          superTypeArguments: undefined,
          typeParameters: undefined,
          range: [ 0, 33 ],
          loc: { end: [Object], start: [Object] },
          parent: {
            type: 'Program',
            range: [Array],
            body: [Array],
            comments: [],
            sourceType: 'module',
            tokens: [Array],
            loc: [Object],
            parent: null
          }
        }
      }
    }
  }
}

Node.js v24.14.1

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions