TypeScript: [4.2.2] Compiler crash with null pointer in tsc.js: isWeakType resolved.callSignatures is null

Bug Report

πŸ”Ž Search Terms

resolved.callSignatures

πŸ•— Version & Regression Information

  • This is a crash
  • This changed between versions 4.1.0 and 4.2.2

⏯ Playground Link

Playground link with relevant code

πŸ’» Code

// We can quickly address your report if:
//  - The code sample is short. Nearly all TypeScript bugs can be demonstrated in 20-30 lines of code!
//  - It doesn't use external libraries. These are often issues with the type definitions rather than TypeScript bugs.
//  - The incorrectness of the behavior is readily apparent from reading the sample.
// Reports are slower to investigate if:
//  - We have to pare too much extraneous code.
//  - We have to clone a large repo and validate that the problem isn't elsewhere.
//  - The sample is confusing or doesn't clearly demonstrate what's wrong.

source code:

function isWeakType(type) {
    if (type.flags & 524288) {
        var resolved = resolveStructuredTypeMembers(type);
        return resolved.callSignatures.length === 0 && resolved.constructSignatures.length === 0 &&
            !resolved.stringIndexInfo && !resolved.numberIndexInfo &&
            resolved.properties.length > 0 &&
            ts.every(resolved.properties, function (p) { return !!(p.flags & 16777216); });
    }
    if (type.flags & 2097152) {
        return ts.every(type.types, isWeakType);
    }
    return false;
}

error log:

TypeError: Cannot read property 'length' of undefined
    at isWeakType (/Users/jeromeh/Workspaces/experience-core/digitalexp-ui-base/node_modules/typescript/lib/tsc.js:50733:48)
    at isRelatedTo (/Users/jeromeh/Workspaces/experience-core/digitalexp-ui-base/node_modules/typescript/lib/tsc.js:49252:58)
    at checkTypeRelatedTo (/Users/jeromeh/Workspaces/experience-core/digitalexp-ui-base/node_modules/typescript/lib/tsc.js:48974:26)
    at isTypeRelatedTo (/Users/jeromeh/Workspaces/experience-core/digitalexp-ui-base/node_modules/typescript/lib/tsc.js:48938:24)
    at removeSubtypes (/Users/jeromeh/Workspaces/experience-core/digitalexp-ui-base/node_modules/typescript/lib/tsc.js:46041:33)
    at getUnionType (/Users/jeromeh/Workspaces/experience-core/digitalexp-ui-base/node_modules/typescript/lib/tsc.js:46131:26)
    at getWidenedTypeForAssignmentDeclaration (/Users/jeromeh/Workspaces/experience-core/digitalexp-ui-base/node_modules/typescript/lib/tsc.js:42011:28)
    at getTypeOfFuncClassEnumModuleWorker (/Users/jeromeh/Workspaces/experience-core/digitalexp-ui-base/node_modules/typescript/lib/tsc.js:42497:34)
    at getTypeOfFuncClassEnumModule (/Users/jeromeh/Workspaces/experience-core/digitalexp-ui-base/node_modules/typescript/lib/tsc.js:42476:51)
    at getTypeOfSymbol (/Users/jeromeh/Workspaces/experience-core/digitalexp-ui-base/node_modules/typescript/lib/tsc.js:42579:24)

value of the resolved variable at crash time:

Type {
  flags: 524288,
  id: 5978,
  objectFlags: 16,
  symbol: <ref *1> Symbol {
    flags: 33554960,
    escapedName: '_extends',
    declarations: [ [Node] ],
    valueDeclaration: Node {
      pos: 0,
      end: 479,
      kind: 251,
      id: 5476,
      flags: 131072,
      modifierFlagsCache: 536870912,
      transformFlags: 1052704,
      parent: [Node],
      original: undefined,
      decorators: undefined,
      modifiers: undefined,
      symbol: [Symbol],
      localSymbol: undefined,
      locals: Map(0) {},
      nextContainer: [Node],
      name: [Identifier],
      typeParameters: undefined,
      parameters: [Array],
      type: undefined,
      body: [Node],
      asteriskToken: undefined,
      returnFlowNode: [Object],
      jsDocCache: []
    },
    id: undefined,
    mergeId: undefined,
    parent: undefined,
    checkFlags: 0,
    exports: Map(2) { 'default' => [Symbol], '___esModule' => [Symbol] },
    cjsExportMerged: [Circular *1],
    type: Type {
      flags: 524288,
      id: 5976,
      objectFlags: 16,
      symbol: [Circular *1],
      members: [Map],
      properties: undefined,
      callSignatures: undefined,
      constructSignatures: undefined,
      stringIndexInfo: undefined,
      numberIndexInfo: undefined
    },
    resolvedExports: Map(2) { 'default' => [Symbol], '___esModule' => [Symbol] }
  },
  members: Map(2) {
    'default' => Symbol {
      flags: 2097152,
      escapedName: 'default',
      declarations: [Array],
      valueDeclaration: undefined,
      id: 6422,
      mergeId: undefined,
      parent: [Symbol]
    },
    '___esModule' => Symbol {
      flags: 1048580,
      escapedName: '___esModule',
      declarations: [Array],
      valueDeclaration: [Node],
      id: undefined,
      mergeId: undefined,
      parent: [Symbol]
    }
  },
  properties: [
    Symbol {
      flags: 2097152,
      escapedName: 'default',
      declarations: [Array],
      valueDeclaration: undefined,
      id: 6422,
      mergeId: undefined,
      parent: [Symbol]
    },
    Symbol {
      flags: 1048580,
      escapedName: '___esModule',
      declarations: [Array],
      valueDeclaration: [Node],
      id: undefined,
      mergeId: undefined,
      parent: [Symbol]
    }
  ],
  callSignatures: undefined,
  constructSignatures: undefined,
  stringIndexInfo: undefined,
  numberIndexInfo: undefined
}

value of resolved.symbol.declarations[0]: seems to came from @babel/runtime (in v7.13.7 on my node_modules)

<ref *1> Node {
  pos: 0,
  end: 479,
  kind: 251,
  id: 5476,
  flags: 131072,
  modifierFlagsCache: 536870912,
  transformFlags: 1052704,
  parent: <ref *2> Node {
    pos: 0,
    end: 586,
    kind: 297,
    id: 5471,
    flags: 131072,
    modifierFlagsCache: 536870912,
    transformFlags: 32,
    parent: undefined,
    original: undefined,
    statements: [
      [Circular *1],
      [Node],
      [Node],
      pos: 0,
      end: 585,
      hasTrailingComma: false,
      transformFlags: 32
    ],
    endOfFileToken: Token {
      pos: 585,
      end: 586,
      kind: 1,
      id: 0,
      flags: 131072,
      transformFlags: 0,
      parent: [Circular *2]
    },
    fileName: '/Users/jeromeh/Workspaces/experience-core/digitalexp-ui-base/node_modules/@babel/runtime/helpers/extends/index.js',
    text: 'function _extends() {\n' +
      '  module.exports = _extends = Object.assign || function (target) {\n' +
      '    for (var i = 1; i < arguments.length; i++) {\n' +
      '      var source = arguments[i];\n' +
      '\n' +
      '      for (var key in source) {\n' +
      '        if (Object.prototype.hasOwnProperty.call(source, key)) {\n' +
      '          target[key] = source[key];\n' +
      '        }\n' +
      '      }\n' +
      '    }\n' +
      '\n' +
      '    return target;\n' +
      '  };\n' +
      '\n' +
      '  module.exports["default"] = module.exports, module.exports.__esModule = true;\n' +
      '  return _extends.apply(this, arguments);\n' +
      '}\n' +
      '\n' +
      'module.exports = _extends;\n' +
      'module.exports["default"] = module.exports, module.exports.__esModule = true;\n',
    languageVersion: 99,
    languageVariant: 1,
    scriptKind: 1,
    isDeclarationFile: false,
    hasNoDefaultLib: false,
    externalModuleIndicator: undefined,
    bindDiagnostics: [],
    bindSuggestionDiagnostics: undefined,
    pragmas: Map(0) {},
    checkJsDirective: undefined,
    referencedFiles: [],
    typeReferenceDirectives: [],
    libReferenceDirectives: [],
    amdDependencies: [],
    commentDirectives: undefined,
    nodeCount: 129,
    identifierCount: 48,
    identifiers: Map(17) {
      '_extends' => '_extends',
      'module' => 'module',
      'exports' => 'exports',
      'Object' => 'Object',
      'assign' => 'assign',
      'target' => 'target',
      'i' => 'i',
      'arguments' => 'arguments',
      'length' => 'length',
      'source' => 'source',
      'key' => 'key',
      'prototype' => 'prototype',
      'hasOwnProperty' => 'hasOwnProperty',
      'call' => 'call',
      'default' => 'default',
      '__esModule' => '__esModule',
      'apply' => 'apply'
    },
    parseDiagnostics: [],
    path: '/users/jeromeh/workspaces/experience-core/digitalexp-ui-base/node_modules/@babel/runtime/helpers/extends/index.js',
    resolvedPath: '/users/jeromeh/workspaces/experience-core/digitalexp-ui-base/node_modules/@babel/runtime/helpers/extends/index.js',
    originalFileName: '/Users/jeromeh/Workspaces/experience-core/digitalexp-ui-base/node_modules/@babel/runtime/helpers/extends/index.js',
    imports: [],
    moduleAugmentations: [],
    ambientModuleNames: [],
    resolvedModules: undefined,
    additionalSyntacticDiagnostics: [],
    locals: Map(2) { '_extends' => [Symbol], 'module' => [Symbol] },
    nextContainer: [Circular *1],
    commonJsModuleIndicator: Node {
      pos: 21,
      end: 353,
      kind: 216,
      id: 0,
      flags: 131072,
      modifierFlagsCache: 536870912,
      transformFlags: 32,
      parent: [Node],
      original: undefined,
      left: [Node],
      operatorToken: [Token],
      right: [Node],
      symbol: [Symbol]
    },
    symbol: Symbol {
      flags: 512,
      escapedName: '"/Users/jeromeh/Workspaces/experience-core/digitalexp-ui-base/node_modules/@babel/runtime/helpers/extends/index"',
      declarations: [Array],
      valueDeclaration: [Circular *2],
      id: undefined,
      mergeId: undefined,
      parent: undefined,
      exports: [Map]
    },
    symbolCount: 12,
    classifiableNames: Set(2) { 'export=', 'default' },
    jsDocCache: []
  },
  original: undefined,
  decorators: undefined,
  modifiers: undefined,
  symbol: Symbol {
    flags: 16,
    escapedName: '_extends',
    declarations: [ [Circular *1] ],
    valueDeclaration: [Circular *1],
    id: 6415,
    mergeId: 1689,
    parent: undefined,
    isReferenced: 1949695
  },
  localSymbol: undefined,
  locals: Map(0) {},
  nextContainer: <ref *3> Node {
    pos: 68,
    end: 353,
    kind: 208,
    id: 5472,
    flags: 131072,
    modifierFlagsCache: 536875008,
    transformFlags: 1048608,
    parent: Node {
      pos: 51,
      end: 353,
      kind: 216,
      id: 0,
      flags: 131072,
      modifierFlagsCache: 0,
      transformFlags: 32,
      parent: [Node],
      original: undefined,
      left: [Node],
      operatorToken: [Token],
      right: [Circular *3]
    },
    original: undefined,
    decorators: undefined,
    modifiers: undefined,
    symbol: Symbol {
      flags: 16,
      escapedName: '__function',
      declarations: [Array],
      valueDeclaration: [Circular *3],
      id: 6416,
      mergeId: undefined,
      parent: undefined
    },
    localSymbol: undefined,
    locals: Map(4) {
      'target' => [Symbol],
      'i' => [Symbol],
      'source' => [Symbol],
      'key' => [Symbol]
    },
    nextContainer: undefined,
    name: undefined,
    typeParameters: undefined,
    parameters: [
      [Node],
      pos: 79,
      end: 85,
      hasTrailingComma: false,
      transformFlags: 0
    ],
    type: undefined,
    body: Node {
      pos: 86,
      end: 353,
      kind: 230,
      id: 0,
      flags: 131072,
      modifierFlagsCache: 0,
      transformFlags: 1048608,
      parent: [Circular *3],
      original: undefined,
      statements: [Array],
      multiLine: true
    },
    asteriskToken: undefined,
    flowNode: { flags: 6208, antecedent: [Object], node: [Node] },
    returnFlowNode: { flags: 6152, antecedents: [Array], id: 81 },
    jsDocCache: []
  },
  name: Identifier {
    pos: 8,
    end: 17,
    kind: 78,
    id: 0,
    flags: 131072,
    transformFlags: 0,
    parent: [Circular *1],
    original: undefined,
    flowNode: { flags: 6146 },
    originalKeywordKind: undefined,
    escapedText: '_extends'
  },
  typeParameters: undefined,
  parameters: [ pos: 18, end: 18, hasTrailingComma: false, transformFlags: 0 ],
  type: undefined,
  body: Node {
    pos: 19,
    end: 479,
    kind: 230,
    id: 0,
    flags: 131072,
    modifierFlagsCache: 0,
    transformFlags: 1052704,
    parent: [Circular *1],
    original: undefined,
    statements: [
      [Node],
      [Node],
      [Node],
      pos: 21,
      end: 477,
      hasTrailingComma: false,
      transformFlags: 1052704
    ],
    multiLine: true
  },
  asteriskToken: undefined,
  returnFlowNode: {
    flags: 2064,
    antecedent: { flags: 2304, antecedent: [Object], node: [Node] },
    node: Node {
      pos: 401,
      end: 427,
      kind: 201,
      id: 0,
      flags: 131072,
      modifierFlagsCache: 536870912,
      transformFlags: 0,
      parent: [Node],
      original: undefined,
      expression: [Node],
      name: [Identifier],
      symbol: [Symbol],
      flowNode: [Object]
    }
  },
  jsDocCache: []
}

πŸ™ Actual behavior

Crash

πŸ™‚ Expected behavior

Don’t crash

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Comments: 30 (9 by maintainers)

Commits related to this issue

Most upvoted comments

I managed to create a smaller example:

package.json
{
  "name": "test-module",
  "version": "1.0.0",
  "scripts": {
    "build": "tsc --outDir lib/"
  },
  "dependencies": {
    "typescript": "4.2.2"
  }
}
tsconfig.json
{
  "compilerOptions": {
    "allowJs": true,
    "esModuleInterop": true,
    "noEmit": true,
    "baseUrl": "."
  },
  "include": ["src"]
}
src/index.ts
import dep from "./dep.js";

dep();
src/dep.js
function fn() {}
module.exports = fn;
module.exports = fn;
module.exports["default"] = module.exports;

ts-error-2.zip

@paztis as a workaround downgrade @babel/runtime to 7.12, since it contains the file where TS crashes

@paztis We’ll put this into the next 4.2 release (4.2.3 ~4.3.2~)

Edit: Disastrously confusing typo; thanks @andrewbranch