microsoft/TypeScript · error · TypeError

Function expected

Error message

Function expected

What it means

TypeScript emits `__esDecorate` into downleveled output to support TC39 decorators on older runtimes. Its internal `accept(f)` rejects any value that is neither `undefined` nor a function — it validates decorator return values (get/set/init/value) and addInitializer callbacks. A decorator that returns a defined non-function triggers this TypeError at runtime.

Source

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

    name: "typescript:param",
    importName: "__param",
    scoped: false,
    priority: 4,
    text: `
            var __param = (this && this.__param) || function (paramIndex, decorator) {
                return function (target, key) { decorator(target, key, paramIndex); }
            };`,
};

// ES Decorators Helpers
const esDecorateHelper: UnscopedEmitHelper = {
    name: "typescript:esDecorate",
    importName: "__esDecorate",
    scoped: false,
    priority: 2,
    text: `
        var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
            function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
            var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
            var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
            var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
            var _, done = false;
            for (var i = decorators.length - 1; i >= 0; i--) {
                var context = {};
                for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
                for (var p in contextIn.access) context.access[p] = contextIn.access[p];
                context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
                var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
                if (kind === "accessor") {
                    if (result === void 0) continue;
                    if (result === null || typeof result !== "object") throw new TypeError("Object expected");
                    if (_ = accept(result.get)) descriptor.get = _;
                    if (_ = accept(result.set)) descriptor.set = _;
                    if (_ = accept(result.init)) initializers.unshift(_);
                }
                else if (_ = accept(result)) {

View on GitHub (pinned to b465fdbfe1)

Solutions

  1. Make the decorator return either `undefined` or a function for the decorated kind.
  2. Pass a function reference to addInitializer (not the result of calling one).
  3. Raise `target` to a runtime with native decorator support to drop the helper.
  4. Unit-test decorators against the emitted helper to catch shape violations early.

Example fix

// before
function deco(value, ctx) { return 42; }   // non-function -> "Function expected"
class A { @deco m() {} }

// after
function deco(value, ctx) { return () => {}; }  // function (or undefined)
class A { @deco m() {} }
Defensive patterns

Strategy: type-guard

Validate before calling

function validateDecoratorResult(v: unknown): void {
  if (v !== undefined && typeof v !== "function") {
    throw new TypeError("Decorator must return undefined or a function for this kind.");
  }
}

Type guard

function isAcceptedDecoratorValue(v: unknown): v is undefined | Function {
  return v === undefined || typeof v === "function";
}

Prevention

When it happens

Trigger: A class-element decorator returns a non-function value (e.g. a number, string, or object) for a method/field/value; or `context.addInitializer(<non-function>)` is called.

Common situations: Porting a decorator that returns the wrong shape; a buggy third-party decorator library; calling addInitializer with the result of an invocation instead of a function reference.

Related errors


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