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
- Make the decorator return either `undefined` or a function for the decorated kind.
- Pass a function reference to addInitializer (not the result of calling one).
- Raise `target` to a runtime with native decorator support to drop the helper.
- 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
- Return either undefined or a function from class-element decorators.
- Pass function references (not call results) to context.addInitializer.
- Add unit tests that exercise decorators against the emitted __esDecorate helper.
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
- Cannot add initializers after decoration has completed
- Object expected
- Symbol.asyncIterator is not defined.
- Class extends value ${String(b)} is not a constructor or nul
- Object is not iterable.
AI-assisted analysis of microsoft/TypeScript@b465fdbfe1 (2026-08-12).
Data as JSON: /api/errors/ae45fa848714b20d.
Report an issue: GitHub.