microsoft/TypeScript · error · TypeError

Class extends value ${String(b)} is not a constructor or nul

Error message

Class extends value ${String(b)} is not a constructor or null

What it means

`__extends` downlevels class heritage for ES5 targets. It throws if the base value `b` is neither a function nor null, because only a constructor (or null) is a legal class-extends target.

Source

Thrown at src/compiler/factory/emitHelpers.ts:950

// ES2015 Helpers

const extendsHelper: UnscopedEmitHelper = {
    name: "typescript:extends",
    importName: "__extends",
    scoped: false,
    priority: 0,
    text: `
            var __extends = (this && this.__extends) || (function () {
                var extendStatics = function (d, b) {
                    extendStatics = Object.setPrototypeOf ||
                        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
                        function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
                    return extendStatics(d, b);
                };

                return function (d, b) {
                    if (typeof b !== "function" && b !== null)
                        throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
                    extendStatics(d, b);
                    function __() { this.constructor = d; }
                    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
                };
            })();`,
};

const templateObjectHelper: UnscopedEmitHelper = {
    name: "typescript:makeTemplateObject",
    importName: "__makeTemplateObject",
    scoped: false,
    priority: 0,
    text: `
            var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) {
                if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; }
                return cooked;
            };`,
};

View on GitHub (pinned to b465fdbfe1)

Solutions

  1. Ensure the extended expression evaluates to a constructor (class/function) or null.
  2. Resolve circular imports so the base is fully initialized before the subclass definition runs.
  3. If extending null intentionally, write `extends null` explicitly.

Example fix

// before
// a.js: export const Base = 5;        // not a constructor
// b.js: import { Base } from "./a"; class Sub extends Base {}  // throws

// after
// a.js: export class Base {}
// b.js: import { Base } from "./a"; class Sub extends Base {}
Defensive patterns

Strategy: type-guard

Validate before calling

function assertExtensible(base: unknown): void {
  if (typeof base !== "function" && base !== null) {
    throw new TypeError(`Class extends value ${String(base)} is not a constructor or null`);
  }
}

Type guard

function isConstructorOrNull(v: unknown): v is (new (...args: any[]) => any) | null {
  return v === null || typeof v === "function";
}

Prevention

When it happens

Trigger: `class X extends Y` where Y evaluates at runtime to a non-function, non-null value: a number, string, plain object, or `undefined`.

Common situations: Circular import causing the base to be undefined at class-evaluation time; a mixin computed to a non-function; extending a const before its declaration (TDZ-like effect in transpiled output).

Related errors


AI-assisted analysis of microsoft/TypeScript@b465fdbfe1 (2026-08-12). Data as JSON: /api/errors/e8869c915c50b073. Report an issue: GitHub.