angular/angular-cli · error · Error
Memoize decorator can only be used on methods or get accesso
Error message
Memoize decorator can only be used on methods or get accessors.
What it means
The `memoize` decorator (a TC39 decorator wrapping methods/getters) checks `context.kind` and only supports `'method'` and `'getter'` member kinds. Applying `@memoize` to any other kind (setter, field, or a plain function in a context where kind differs) is rejected at decoration time, since caching semantics only make sense for parameterless-ish calls and accessors.
Source
Thrown at packages/angular/cli/src/utilities/memoize.ts:21
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/
/**
* A decorator that memoizes methods and getters.
*
* **Note**: Be cautious where and how to use this decorator as the size of the cache will grow unbounded.
*
* @see https://en.wikipedia.org/wiki/Memoization
*/
export function memoize<This, Args extends unknown[], Return>(
target: (this: This, ...args: Args) => Return,
context: ClassMemberDecoratorContext,
) {
if (context.kind !== 'method' && context.kind !== 'getter') {
throw new Error('Memoize decorator can only be used on methods or get accessors.');
}
const cache = new Map<string, Return>();
return function (this: This, ...args: Args): Return {
for (const arg of args) {
if (!isJSONSerializable(arg)) {
throw new Error(
`Argument ${isNonPrimitive(arg) ? arg.toString() : arg} is JSON serializable.`,
);
}
}
const key = JSON.stringify(args);
if (cache.has(key)) {
return cache.get(key) as Return;
}
View on GitHub (pinned to bb72145f9a)
Solutions
- Apply `@memoize` only to methods or `get` accessors.
- If you need a cached property, convert the field to a `get` accessor: `@memoize get value() {...}`.
- Remove the decorator from setters; caching a setter is not meaningful — cache the corresponding getter instead.
- If memoizing a free function, wrap it manually with a Map-based cache instead of the decorator.
Example fix
// before
class C {
@memoize set foo(v: string) { this._v = v; }
}
// after
class C {
@memoize get foo() { return computeFoo(); }
set foo(v: string) { this._v = v; }
} Defensive patterns
Strategy: type-guard
Validate before calling
// At class-definition time, only decorate methods/getters:
class C {
@memoize
get value(): number { return expensive(); }
} Type guard
function supportsMemoize(ctx: ClassMemberDecoratorContext): boolean {
return ctx.kind === 'method' || ctx.kind === 'getter';
} Try / catch
// Decoration errors surface at class definition; wrap module evaluation if dynamic:
try {
const mod = await import('./decorated-module.js');
} catch (e) {
if (e instanceof Error && e.message.includes('Memoize decorator can only be used')) {
console.error('Fix the @memoize target: use a method or getter.');
} else { throw e; }
} Prevention
- Only place @memoize on methods or get accessors.
- Never apply @memoize to setters, fields, or static initializers.
- Convert lazily-computed fields to getters to use memoize.
- Enable strict decorator typing so TypeScript flags misuse early.
When it happens
Trigger: Decorating a class setter (`set foo(v)`), a class field, or another unsupported class member with `@memoize`, evaluated when the class is defined.
Common situations: Refactoring a getter into a setter while keeping the decorator; applying the decorator to a property intended as a lazily-computed value (should be a getter instead); copy-pasting the decorator onto the wrong member.
Related errors
- Argument ${isNonPrimitive(arg) ? arg.toString() : arg} is JS
- Expected a JobHandler as second argument.
- Expected an object options as second argument.
- Expected name to be a string.
- Unrecognized arguments.
AI-assisted analysis of angular/angular-cli@bb72145f9a (2026-08-30).
Data as JSON: /api/errors/91e77ac42257d7b5.
Report an issue: GitHub.