Skip to content

Parameter binding ​

Parameter decorators bind arguments by index, not by their declared TypeScript type. Explicit names survive minification and are the reliable choice for path/query/header fields.

Binding matrix ​

parameter(type: ParameterType, name = '') returns a legacy method-parameter decorator. ParameterMetadata stores type, optional name, index, and optional explicit (whether the name was given to the decorator rather than inferred); PARAMETER_METADATA_KEY is the Symbol used on the target/property.

Arguments are bound by shape. Only a plain object (an object literal or Object.create(null)) is spread into its keys; any other value, including an array, a Date or a class instance, is bound to the parameter's name (explicit, else inferred, else param${index}) and serialized by fetcher.

Factory / ParameterTypeOther argument (scalar, array, Date, instance)Plain object argumentNullish behavior
path(name = '') / PATHBind to the parameter nameSpread entries, ignoring provided nameSkip a null/undefined argument or entry
query(name = '') / QUERYBind to the parameter name; an array repeats the key (ids=1&ids=2), a Date is sent as ISO 8601Spread entriesSkip a null/undefined argument or entry
header(name = '') / HEADERSet the header named after the parameter; an array is joined with , , a Date is sent as ISO 8601Set one header per entry, case-insensitivelySkip entire null/undefined argument; a null/undefined entry deletes that header
body() / BODYWhole request bodyWhole request bodyAssigned as supplied before request merging
request() / REQUESTExpect ParameterRequestMerge into resolved request lastFalsy argument becomes empty request
attribute(name = '') / ATTRIBUTEStored under the parameter nameExplicit name: stored whole under it; unnamed: entries mergedUndefined is skipped; null is stored like any other value

An explicitly named @attribute('user') stores its value under user whatever it is. An unnamed @attribute() merges a Map or plain object entry by entry and stores anything else under the inferred name.

Arguments are processed left-to-right; later bindings win. Body and request bindings are single selected values, so the last such parameter wins rather than merging multiple request arguments. Unannotated ordinary arguments are ignored.

ParameterRequest<BODY> extends FetchRequestInit<BODY> and PathCapable. Its path changes the endpoint path; use urlParams.path for replacement values. It can override method, headers, body, timeout, signal, and native Fetch fields, following mergeRequest, including its nullish fallback rules. An empty-string parameter path does not override a nonempty endpoint path.

The replacement method receives only the actual argument list; default parameter expressions in the original placeholder method do not execute. Pass defaults explicitly or configure urlParams metadata.

Names and reflection ​

getParameterNames(func): string[] parses Function.toString(), caches by function in a WeakMap, and returns an empty array on parsing failure; non-functions throw TypeError before parsing. It splits on top-level commas (commas and brackets inside defaults, strings and comments do not split) and strips annotations and defaults. A destructured parameter yields '', which keeps later names at their index; a rest parameter yields its name without .... Minified names are not a stable naming contract.

getParameterName(target, propertyKey, index, providedName?) returns a truthy explicit name first, then an inferred name, otherwise undefined (a destructured parameter has no inferred name). Bound values without a resolved name fall back to param${index}. An unnamed @path() whose inferred name matches no placeholder of the path template (read in the fetcher's urlTemplateStyle) logs a warning once per endpoint: that is what a minifier renaming the parameter looks like. A plain-object argument (spread into its keys) does not warn. Placeholders with no parameter are not reported, since an interceptor may fill them (cosec fills {tenantId}/{ownerId}); if nothing does, resolving the URL fails with Missing required path parameter.

Cancellation and inherited metadata ​

An AbortSignal or AbortController argument is recognized before decorator metadata, even without a decorator. If multiple are supplied the last of each kind wins; a request parameter can override them. A signal or controller applies together with the Fetcher timeout, whichever fires first, as described in cancellation.

Parameter metadata uses copy-on-write when inherited, so decorating an override does not mutate the parent's Map. An override without its own endpoint decorator keeps its own implementation; @api does not replace it with the parent's request. Class binding walks inherited string- and symbol-named methods. Static methods are not part of that binding traversal. Keep explicit parameter names on inherited/overridden endpoints too.

Complete example ​

ts
import {
  api,
  post,
  path,
  query,
  body,
  request,
  autoGeneratedError,
  type ParameterRequest,
} from '@ahoo-wang/fetcher-decorator';

type User = { id: string; name: string };
@api('/users')
class Users {
  @post('/{id}')
  update(
    @path('id') id: string,
    @query('notify') notify: boolean,
    @body() value: { name: string },
    @request() options?: ParameterRequest,
    signal?: AbortSignal,
  ): Promise<User> {
    throw autoGeneratedError(id, notify, value, options, signal);
  }
}
const users = new Users();
async function updateUser() {
  const controller = new AbortController();
  return users.update(
    '1',
    true,
    { name: 'Ada' },
    { headers: { 'X-Trace-Id': 'demo' } },
    controller.signal,
  );
}
void updateUser;

Public symbols and source ​

SymbolImplementation
ParameterTypeparameterDecorator.ts:19
ParameterMetadataparameterDecorator.ts:136
PARAMETER_METADATA_KEYparameterDecorator.ts:168
parameterparameterDecorator.ts:206
pathparameterDecorator.ts:273
queryparameterDecorator.ts:305
headerparameterDecorator.ts:337
bodyparameterDecorator.ts:355
ParameterRequestparameterDecorator.ts:367
requestparameterDecorator.ts:387
attributeparameterDecorator.ts:423
getParameterNamesreflection.ts:51
getParameterNamereflection.ts:97

Package index

Released under the Apache License 2.0.