(
+ options?: MemoizeOptions,
+): (...args: Args) => AnyDecoratorReturn {
+ // ... implementation here ...
+}
+
+@memoize @memoizeFactory()
+class Foo {
+ @memoize
+ bar = 42;
+
+ @memoizeFactory({ maxAge: 1000 })
+ baz() {
+ return "qux";
+ }
+
+ @memoize
+ @memoizeFactory({})
+ get quux() {
+ return Math.random() * 1e6 | 0;
+ }
+}
+```
+
+---
+
+
+
+##### **[MIT]** © **[Nicholas Berlette]**. All rights reserved.
+
+###### [Read the Docs][Docs] · [View Source][GitHub] · [Squash a Bug][Issues]
+
+
+
+[![][badge-jsr-decorators] ![][badge-jsr] ![][badge-jsr-score]][jsr]
+
+
+
+[@decorators/types]: https://github.com/nberlette/decorators/tree/main/packages/types#readme "Check out '@decorators/types' and more decorator packages in our GitHub monorepo!"
+[GitHub]: https://github.com/nberlette/decorators/tree/main/packages/types#readme "Check out '@decorators/types' and more decorator packages in our GitHub monorepo!"
+[MIT]: https://nick.mit-license.org "MIT © 2024+ Nicholas Berlette. All rights reserved."
+[Nicholas Berlette]: https://github.com/nberlette "Nicholas Berlette's GitHub Profile"
+[Issues]: https://github.com/nberlette/decorators/issues/new?assignees=nberlette&labels=types,bugs&title=%5Btypes%5D+ "Found a bug? Let's squash it!"
+[deno]: https://deno.land "Deno's Official Website"
+[jsr]: https://jsr.io/@decorators/types "View the @decorators/types package on jsr.io/@decorator/types"
+[docs]: https://jsr.io/@decorators/types "View @decorators API docs"
+[`1.40.0` release]: https://deno.land/blog/1.40 "Deno 1.40.0 Release Notes"
+[TC39 Decorators Proposal]: https://github.com/tc39/proposal-decorators "TC39 Proposal: Decorators"
+[bun]: https://bun.sh "Bun: a new runtime, bundler, package manager for TypeScript / TSX"
+[pnpm]: https://pnpm.io "PNPM Package Manager"
+[yarn]: https://yarnpkg.com "Yarn Package Manager"
+[@]: https://api.iconify.design/streamline:mail-sign-at-email-at-sign-read-address.svg?width=2.5rem&height=1.4rem&color=%23fa0
+[badge-jsr-decorators]: https://jsr.io/badges/@decorators "jsr.io/@decorators"
+[badge-jsr]: https://jsr.io/badges/@decorators/types "jsr.io/@decorators/types"
+[badge-jsr-score]: https://jsr.io/badges/@decorators/types/score "jsr.io/@decorators/types"
+[badge-pnpm]: https://api.iconify.design/logos:pnpm.svg?height=1.3rem&inline=true "PNPM"
+[badge-bun]: https://api.iconify.design/logos:bun.svg?height=1.5rem&inline=true "Bun"
+[badge-yarn]: https://api.iconify.design/logos:yarn.svg?height=1.5rem&inline=true "Yarn"
+[badge-npm-2]: https://api.iconify.design/logos:npm.svg?height=1rem&inline=true "NPM"
+[badge-deno-2]: https://api.iconify.design/logos:deno.svg?height=2rem&width=2.5rem&inline=true
+[badge-function]: https://api.iconify.design/tabler:square-rounded-letter-f-filled.svg?height=1.3rem&color=%232986ff
+[badge-type]: https://api.iconify.design/tabler:square-rounded-letter-t-filled.svg?height=1.3rem&color=orchid
diff --git a/packages/types/_internal.ts b/packages/types/_internal.ts
new file mode 100644
index 0000000..e7061c9
--- /dev/null
+++ b/packages/types/_internal.ts
@@ -0,0 +1,96 @@
+// deno-lint-ignore-file no-explicit-any
+
+import type { ClassAccessorDecoratorFunction } from "./accessor.ts";
+import type { ClassDecoratorFunction } from "./class.ts";
+import type { ClassFieldDecoratorFunction } from "./field.ts";
+import type { ClassGetterDecoratorFunction } from "./getter.ts";
+import type { LegacyAccessorDecoratorFunction } from "./legacy/accessor.ts";
+import type { LegacyClassDecoratorFunction } from "./legacy/class.ts";
+import type { LegacyMethodDecoratorFunction } from "./legacy/method.ts";
+import type { LegacyParameterDecoratorFunction } from "./legacy/parameter.ts";
+import type { LegacyPropertyDecoratorFunction } from "./legacy/property.ts";
+import type { ClassMethod, ClassMethodDecoratorFunction } from "./method.ts";
+import type { ClassSetterDecoratorFunction } from "./setter.ts";
+import type {
+ Constructor,
+ Is,
+ KeyOf,
+ ValueOf,
+} from "jsr:@decorators/internal@^0.1.3";
+export * from "jsr:@type/union@^0.1.0";
+export * from "jsr:@decorators/internal@^0.1.3/assert";
+export * from "jsr:@decorators/internal@^0.1.3/types";
+export type { Is } from "jsr:@decorators/internal@^0.1.3/types";
+
+/**
+ * Extracts the Parameters of a given decorator.
+ */
+export type DecoratorParameters = T extends
+ (...args: infer A) => any
+ ? Is, Readonly>>>
+ : Fallback;
+
+export interface DecoratorTypeMap<
+ This = any,
+ Value = any,
+> {
+ "class": ClassDecoratorFunction<
+ InstanceType>,
+ Is
+ >;
+ "field": ClassFieldDecoratorFunction;
+ "accessor": ClassAccessorDecoratorFunction;
+ "getter": ClassGetterDecoratorFunction;
+ "setter": ClassSetterDecoratorFunction;
+ "method": ClassMethodDecoratorFunction>>;
+}
+
+export interface LegacyDecoratorTypeMap<
+ This = any,
+ Value = any,
+ Key extends KeyOf> = KeyOf>,
+> {
+ "legacy:class": LegacyClassDecoratorFunction<
+ InstanceType>,
+ Is
+ >;
+ "legacy:parameter": LegacyParameterDecoratorFunction, Key>;
+ "legacy:field": LegacyPropertyDecoratorFunction, Key>;
+ "legacy:accessor": LegacyAccessorDecoratorFunction<
+ Is,
+ Value,
+ Key
+ >;
+ "legacy:method": LegacyMethodDecoratorFunction, Value, Key>;
+}
+
+export type AnyDecoratorTypeMap<
+ This = any,
+ Value = any,
+ Key extends KeyOf> = KeyOf>,
+> =
+ & DecoratorTypeMap
+ & LegacyDecoratorTypeMap;
+
+export type DecoratorArgsTypeMap<
+ This = any,
+ Value = any,
+ Key extends KeyOf> = KeyOf>,
+ AsEntries extends boolean = false,
+ Map extends Record = AnyDecoratorTypeMap<
+ This,
+ Value,
+ Key
+ >,
+> = {
+ readonly [P in keyof Map]-?: [AsEntries] extends [true]
+ ? [Map[P], Readonly>]
+ : Readonly>;
+} extends infer V ? V : never;
+
+export function __throw(error: string | Error): never {
+ error = typeof error === "string" ? new Error(error) : error;
+ Error.captureStackTrace?.(error, __throw);
+ error.stack?.slice();
+ throw error;
+}
diff --git a/packages/types/accessor.ts b/packages/types/accessor.ts
new file mode 100644
index 0000000..1daaf3a
--- /dev/null
+++ b/packages/types/accessor.ts
@@ -0,0 +1,111 @@
+/**
+ * @module accessor
+ *
+ * This module provides types for working with class auto-accessors according
+ * to the latest version of the TC39 Decorators Proposal (now at Stage 3).
+ *
+ * The types in this module provide a structured and well-documented
+ * foundation for creating consistent auto-accessor decorators with easily
+ * predictable behavior. Auto-accessors are a new type of class member
+ * introduced in the latest version of the Decorators Proposal, and introduce
+ * a new `accessor` keyword, which scaffolds a `getter`/`setter` pair backed
+ * by a private field to store the value.
+ *
+ * @example
+ * ```ts
+ * import type { ClassAccessorDecoratorFunction } from "@decorators/types/accessor";
+ *
+ * const log = (prefix: string): ClassAccessorDecoratorFunction =>
+ * (_, context) => {
+ * console.log(`[${prefix}] Initializing ${String(context.name)}`);
+ * };
+ *
+ * class Example {
+ * @log("Example") accessor field = "value";
+ * }
+ * ```
+ * @category Auto-Accessor Decorators
+ */
+
+/**
+ * Represents the decorator signature applied to a class auto-accessor member.
+ *
+ * #### What are auto-accessors?
+ *
+ * The latest form of the Decorators Proposal introduces a brand new type of
+ * class member and an entirely new `"accessor"` keyword. These members are
+ * known as "auto-accessors", and their decorators are "auto-accessor
+ * decorators".
+ *
+ * These behave just like a regular class field at runtime, but are backed by
+ * a private field to store the value. This allows the decorator to access the
+ * field's value at runtime, and also to replace the field's value with a new
+ * value.
+ *
+ * The purpose of this new language feature is to provide a remedy for the
+ * shortcomings of field decorators, which are explained in the comments on
+ * the {@linkcode ClassFieldDecoratorFunction} type. Auto-accessors seek to provide an
+ * alternative solution that offers the functionality that field decorators
+ * lack, while behaving **_close_** to how a standard field behaves at
+ * runtime.
+ *
+ * It's important to note that **these are not fields**. They are auto-created
+ * getters / setters that are backed by a private field for storage.
+ *
+ * ### Target Argument
+ *
+ * This is the only type of decorator that receives an object for its target
+ * argument, which is a special descriptor-style object containing the
+ * original `get` and `set` methods of the auto-accessor.
+ *
+ * ### Context Argument
+ *
+ * The `context` argument is a {@linkcode ClassAccessorDecoratorContext}
+ * object containing the metadata and other information about the
+ * auto-accessor being decorated. It's `kind` property will always be
+ * `"accessor"`.
+ *
+ * Similar to the other decorator types, it also includes an `addInitializer`
+ * method, `name` and `metadata` properties. And like all class member
+ * decorators, it also has `access`, `static`, and `private` properties.
+ *
+ * Since the `target` argument has a `get` and a `set` property, you can
+ * expect to find a `has`, `get`, and `set` method on the `context.access`
+ * object.
+ *
+ * ### Return Value
+ *
+ * The return value of an auto-accessor decorator may either be `void` (if no
+ * changes are needed), or a {@linkcode ClassAccessorDecoratorResult} object.
+ * This is an object similar to the target object, with `get` and/or `set`
+ * methods, and also optionally an `init` method.
+ *
+ * These optional methods are used to replace the original `get` or `set`
+ * methods, or to provide a custom initialization function for the
+ * auto-accessor's private backing field, respectively. The `init` method
+ * shares the same signature as {@linkcode ClassFieldDecoratorResult}.
+ *
+ * @template This The type on which the class element will be defined. For a
+ * static class element, this is the type of the constructor. For non-static
+ * class elements, this will be the type of the instance.
+ * @template Value The type of the class auto-accessor's value.
+ * @category Auto-Accessor Decorators
+ */
+export interface ClassAccessorDecoratorFunction<
+ This = unknown,
+ Value = unknown,
+ Return extends void | ClassAccessorDecoratorResult =
+ | void
+ | ClassAccessorDecoratorResult,
+> {
+ /**
+ * @param target The descriptor-style object containing the original `get`
+ * and `set` methods of the auto-accessor.
+ * @param context The context object for the auto-accessor decorator.
+ * @returns Either `void` or a {@link ClassAccessorDecoratorResult} object.
+ */
+ (
+ target: ClassAccessorDecoratorTarget,
+ context: ClassAccessorDecoratorContext,
+ ): Return;
+}
diff --git a/packages/types/class.ts b/packages/types/class.ts
new file mode 100644
index 0000000..eb1e59c
--- /dev/null
+++ b/packages/types/class.ts
@@ -0,0 +1,72 @@
+/**
+ * @module class
+ *
+ * This module provides types for working with class decorators according to
+ * the latest version of the TC39 Decorators Proposal (now at Stage 3).
+ *
+ * The types in this module provide a structured and well-documented foundation
+ * for creating consistent class decorators with easily predictable behavior.
+ *
+ * @example
+ * ```ts
+ * import type { ClassDecoratorFunction } from "@decorators/types/class";
+ *
+ * const log = (prefix: string): ClassDecoratorFunction => (target, context) => {
+ * console.log(`[${prefix}] Initializing ${String(context.name)}`);
+ * };
+ *
+ * @log("Example")
+ * class Example {
+ * // ...
+ * }
+ * ```
+ * @category Class Decorators
+ */
+import type { Constructor } from "./_internal.ts";
+
+/**
+ * Represents a class decorator function's signature.
+ *
+ * #### Target Argument
+ *
+ * The `target` argument is the class constructor itself. This is the only
+ * type of decorator that receives a constructor as its first argument.
+ *
+ * #### Context Argument
+ *
+ * The `context` argument is a {@linkcode ClassDecoratorContext} object, which
+ * contains the metadata and other information about the class being
+ * decorated. The `kind` property of this object will always be `"class"`.
+ * The `name` property will be the name of the class being decorated, or
+ * `undefined` if it is an anonymous class / class expression. The
+ * `addInitializer` method (found in all decorator context objects) allows the
+ * registration of callback functions that will then be executed at the time
+ * of initialization. The `this` context binding will be the class constructor
+ * in this instance.
+ *
+ * It also has a `metadata` property, which is shared across all decorators
+ * applied to the same class, and goes on to become the `[Symbol.metadata]`
+ * property of the class constructor once all decorators have been applied.
+ *
+ * @template {AbstractClass} Class The type of the class
+ * constructor. This is the type of the {@link target} argument, and will be
+ * the type of the contextual `this` binding for any hooks registered with the
+ * {@linkcode addInitializer} method, as well as any static class members.
+ * @template {object} [Proto=object] The type of the class prototype. This is
+ * the type of the contextual `this` binding for any instance class members,
+ * as well as the body of the class itself and its constructor function.
+ * @template {void | Class} [Return=void|Class] The return type of the class
+ * decorator function. This may be `void` if the decorator does not need to
+ * return a replacement constructor; otherwise it **must** return the same type
+ * of constructor as the original class it is decorating (or a subclass
+ * thereof). No additional properties may be added by a decorator, unless they
+ * were already present on the original class prior to decoration.
+ * @category Class Decorators
+ */
+export interface ClassDecoratorFunction<
+ Proto extends object = object,
+ Class extends Constructor = Constructor,
+ Return extends void | Class = void | Class,
+> {
+ (target: Class, context: ClassDecoratorContext): Return;
+}
diff --git a/packages/types/deno.json b/packages/types/deno.json
new file mode 100644
index 0000000..744a5e5
--- /dev/null
+++ b/packages/types/deno.json
@@ -0,0 +1,36 @@
+{
+ "name": "@decorators/types",
+ "version": "0.1.3",
+ "exports": {
+ ".": "./mod.ts",
+ "./class": "./class.ts",
+ "./method": "./method.ts",
+ "./field": "./field.ts",
+ "./accessor": "./accessor.ts",
+ "./getter": "./getter.ts",
+ "./setter": "./setter.ts",
+ "./guards": "./guards.ts",
+ "./utilities": "./utilities.ts",
+ "./signatures": "./signatures.ts",
+ "./legacy": "./legacy.ts",
+ "./legacy/class": "./legacy/class.ts",
+ "./legacy/guards": "./legacy/guards.ts",
+ "./legacy/method": "./legacy/method.ts",
+ "./legacy/property": "./legacy/property.ts",
+ "./legacy/accessor": "./legacy/accessor.ts",
+ "./legacy/parameter": "./legacy/parameter.ts",
+ "./legacy/utilities": "./legacy/utilities.ts"
+ },
+ "publish": {
+ "include": [
+ "**/*.ts",
+ "*.json",
+ "*.md",
+ "LICENSE"
+ ],
+ "exclude": [
+ "*.test.*",
+ "**/test*"
+ ]
+ }
+}
diff --git a/packages/types/field.ts b/packages/types/field.ts
new file mode 100644
index 0000000..0e46e9a
--- /dev/null
+++ b/packages/types/field.ts
@@ -0,0 +1,95 @@
+/**
+ * @module field
+ *
+ * This module provides types for working with class field decorators
+ * according to the latest version of the TC39 Decorators Proposal (now at
+ * Stage 3).
+ *
+ * The types in this module provide a structured and well-documented
+ * foundation for creating consistent field decorators with easily predictable
+ * behavior.
+ *
+ * @example
+ * ```ts
+ * import type { ClassFieldDecoratorFunction } from "@decorators/types/field";
+ *
+ * const log = (prefix: string): ClassFieldDecoratorFunction => (_, context) => (initialValue) => {
+ * console.log(
+ * `[${prefix}] Initializing ${String(context.name)} with ${initialValue}`,
+ * );
+ * return initialValue;
+ * };
+ *
+ * class Example {
+ * @log("Example") static staticField = "static";
+ * }
+ * ```
+ * @category Field Decorators
+ */
+
+/**
+ * Represents the decorator signature applied to a class field. This is the
+ * only decorator type that will always have `undefined` as its first
+ * argument, and receives a {@linkcode ClassFieldDecoratorContext} object for
+ * its second argument.
+ *
+ * Field decorators are able to return a custom initializer function, which
+ * can be used to mutate or replace the original initial value of the field.
+ * See the {@linkcode ClassFieldDecoratorResult} type for more information.
+ *
+ * @template This The type on which the class element will be defined. For a
+ * static class element, this is the type of the constructor. For non-static
+ * class elements, this will be the type of the instance.
+ * @template Value The type of the class field's value.
+ * @category Field Decorators
+ */
+export interface ClassFieldDecoratorFunction<
+ This = unknown,
+ Value = unknown,
+ Return extends void | ClassFieldDecoratorResult =
+ | void
+ | ClassFieldDecoratorResult,
+> {
+ /**
+ * @param target Always `undefined`.
+ * @param context The context object for the class field decorator.
+ * @returns Either `void` or a custom {@link ClassFieldDecoratorResult} to
+ * initializer the field with a different value.
+ */
+ (
+ target: undefined,
+ context: ClassFieldDecoratorContext,
+ ): Return;
+}
+
+/**
+ * Represents the result of a class field decorator function. This is a custom
+ * initializer function that can be used to modify or replace the initial
+ * value of the field being decorated.
+ *
+ * Inside these custom initializer functions is **the only point** that
+ * initial values of class field are accessible to the decorator, due to the
+ * nature of the initialization process of classes fields by the ECMAScript
+ * language. This is why the `target` parameter of field decorators is always
+ * `undefined` - the field's value is not yet initialized when its decorators
+ * are applied.
+ *
+ * If you'd like to access the value of a field before it's initialized, you
+ * would probably benefit from using an auto-accessor instead of a classic
+ * field. See the {@linkcode ClassAccessorDecoratorFunction} type for more information
+ * on auto-accessors and how to use them.
+ *
+ * @template This The type on which the class element will be defined. For a
+ * static class element, this is the type of the constructor. For non-static
+ * class elements, this will be the type of the instance.
+ * @template Value The type of the class field's value.
+ * @category Field Decorators
+ */
+export interface ClassFieldDecoratorResult {
+ /**
+ * @this This The instance/constructor of the class being decorated.
+ * @param initialValue The initial value of the field being decorated.
+ * @returns The new value to be used as the initial field value.
+ */
+ (this: This, initialValue: Value): Value;
+}
diff --git a/packages/types/getter.ts b/packages/types/getter.ts
new file mode 100644
index 0000000..d090c9b
--- /dev/null
+++ b/packages/types/getter.ts
@@ -0,0 +1,98 @@
+/**
+ * @module getter
+ *
+ * This module provides types for working with class getter decorators
+ * according to the latest version of the TC39 Decorators Proposal (now at
+ * Stage 3).
+ *
+ * The types in this module provide a structured and well-documented
+ * foundation for creating consistent getter decorators with easily
+ * predictable behavior.
+ *
+ * @example
+ * ```ts
+ * import type { ClassGetterDecoratorFunction } from "@decorators/types/getter";
+ *
+ * const log = (): ClassGetterDecoratorFunction =>
+ * (target, context) => {
+ * return function () {
+ * const value = target.call(this);
+ * console.log(`Getting ${String(context.name)} ... ${value}`);
+ * return value;
+ * };
+ * };
+ *
+ * class Example {
+ * #field = "value";
+ *
+ * @log() get field() { return this.#field;
+ * }
+ * }
+ *
+ * const example = new Example();
+ *
+ * example.field; // logs "Getting field ... value"
+ * ```
+ */
+
+/**
+ * Represents a getter method on a class that is being decorated, regardless
+ * of whether its static/instance and public/private.
+ *
+ * @template [This=unknown] The type on which the class element will be
+ * defined. For a static class element, this is the type of the constructor.
+ * For non-static class elements, this will be the type of the instance.
+ * @template [Value=unknown] The type of the getter's return value.
+ * @category Getter Decorators
+ */
+export interface ClassGetter {
+ (this: This): Value;
+}
+
+/**
+ * Represents the decorator signature applied to a class getter member.
+ *
+ * #### What are getters?
+ *
+ * A getter is a special type of method that is used to read the value of a
+ * property. It is defined using the `get` keyword, followed by an identifier
+ * and a block of code that returns the value of the property.
+ *
+ * ### Target Argument
+ *
+ * The `target` argument is the getter method itself, and is a function that
+ * receives no arguments and returns the value of the property.
+ *
+ * ### Context Argument
+ *
+ * The `context` argument is a {@linkcode ClassGetterDecoratorContext} object
+ * containing the metadata and other information about the getter being
+ * decorated. It's `kind` property will always be `"getter"`.
+ *
+ * Similar to the other decorator types, it also includes an `addInitializer`
+ * method, `name` and `metadata` properties. And like all class member
+ * decorators, it also has `access`, `static`, and `private` properties.
+ *
+ * ### Return Value
+ *
+ * The return value of a getter decorator may either be `void` (if no changes
+ * are needed), or a new getter function to replace the original getter.
+ *
+ * @template This The type on which the class element will be defined. For a
+ * static class element, this is the type of the constructor. For non-static
+ * class elements, this will be the type of the instance.
+ * @template Value The type of the class getter.
+ * @category Getter Decorators
+ */
+export interface ClassGetterDecoratorFunction<
+ This = unknown,
+ Value = unknown,
+ Return extends void | ClassGetter =
+ | void
+ | ClassGetter,
+> {
+ (
+ target: ClassGetter,
+ context: ClassGetterDecoratorContext,
+ ): Return;
+}
diff --git a/packages/types/guards.ts b/packages/types/guards.ts
new file mode 100644
index 0000000..e75091a
--- /dev/null
+++ b/packages/types/guards.ts
@@ -0,0 +1,202 @@
+// deno-lint-ignore-file no-explicit-any
+import type { DecoratorArgsTypeMap } from "./_internal.ts";
+import { isLegacyDecoratorArguments } from "./legacy/guards.ts";
+import type { AnyDecoratorArguments, DecoratorArguments } from "./utilities.ts";
+
+/**
+ * Checks if the provided arguments are compatible with a Stage 3 Decorator
+ * function, returning `true` if they are, and `false` if they are not.
+ *
+ * To check if the arguments are compatible with a legacy decorator function,
+ * see {@link isLegacyDecoratorArguments} instead.
+ *
+ * @template {readonly unknown[]} A The tuple of decorator arguments.
+ * @param args The tuple of decorator arguments to check.
+ * @returns {args is DecoratorArguments} `true` if the arguments are compatible
+ * with a Stage 3 decorator function, `false` otherwise.
+ * @example
+ * ```ts
+ * import { isDecoratorArguments } from "@decorators/types";
+ *
+ * function decorator(...args: any[]) {
+ * if (isDecoratorArguments(args)) {
+ * // called as a Stage 3 decorator with no args
+ * return decoratorStage3(...args);
+ * } else {
+ * // called as a decorator factory with args
+ * return (target, context) => decoratorStage3(target, context);
+ * }
+ * }
+ * ```
+ * @category Utilities
+ */
+export function isDecoratorArguments(
+ args: [...A],
+): args is [...Extract>];
+
+/**
+ * Checks if the provided arguments are compatible with a Stage 3 Decorator
+ * function, returning `true` if they are, and `false` if they are not.
+ *
+ * To check if the arguments are compatible with a legacy decorator function,
+ * see {@link isLegacyDecoratorArguments} instead.
+ *
+ * @template {readonly unknown[]} A The tuple of decorator arguments.
+ * @param args The tuple of decorator arguments to check.
+ * @returns {args is DecoratorArguments} `true` if the arguments are compatible
+ * with a Stage 3 decorator function, `false` otherwise.
+ * @example
+ * ```ts
+ * import { isDecoratorArguments } from "@decorators/types";
+ *
+ * function decorator(...args: any[]) {
+ * if (isDecoratorArguments(args)) {
+ * // called as a Stage 3 decorator with no args
+ * return decoratorStage3(...args);
+ * } else {
+ * // called as a decorator factory with args
+ * return (target, context) => decoratorStage3(target, context);
+ * }
+ * }
+ * ```
+ * @category Utilities
+ */
+export function isDecoratorArguments<
+ This,
+ Value,
+>(args: unknown): args is DecoratorArguments;
+
+/** @ignore */
+export function isDecoratorArguments(
+ args: unknown,
+): args is DecoratorArguments {
+ if (Array.isArray(args) && args.length === 2) {
+ const [target, context] = args;
+ return isDecoratorContext(context) && isValidTarget(target, context);
+ }
+ return false;
+}
+
+/**
+ * Checks if the provided arguments are compatible with **any** decorator type,
+ * whether it be a Stage 3 decorator or a Legacy Stage 2 decorator. This uses a
+ * logical OR of {@link isDecoratorArguments} and {@link isLegacyDecoratorArguments} to
+ * determine if the arguments are compatible with either type of decorator.
+ *
+ * @template {readonly unknown[]} A The tuple of decorator arguments.
+ * @param args The tuple of decorator arguments to check.
+ * @returns {args is AnyDecoratorArguments} `true` if the arguments are
+ * compatible with any decorator type, `false` otherwise.
+ * @category Utilities
+ */
+export function isAnyDecoratorArguments<
+ This,
+ Value,
+>(args: unknown): args is AnyDecoratorArguments {
+ return isDecoratorArguments(args) || isLegacyDecoratorArguments(args);
+}
+
+/**
+ * Checks if the provided context object is a valid decorator context object.
+ *
+ * **Note**: this is only compatible with Stage 3 decorators, and will return
+ * `false` if used with legacy decorator arguments.
+ *
+ * @template {DecoratorContext} T The type of decorator context to check.
+ * @param context The context object to check.
+ * @returns {context is T} `true` if the context object is valid, `false` otherwise.
+ */
+export function isDecoratorContext(
+ context: unknown,
+): context is T {
+ if (
+ typeof context === "object" && context != null && !Array.isArray(context)
+ ) {
+ if (
+ "kind" in context && "name" in context && "addInitializer" in context
+ ) {
+ const kinds = [
+ "class",
+ "field",
+ "method",
+ "getter",
+ "setter",
+ "accessor",
+ ];
+ const { kind, name, addInitializer } =
+ (context ?? {}) as DecoratorContext;
+ if (
+ (typeof addInitializer !== "function") ||
+ (typeof kind !== "string" || !kinds.includes(kind)) ||
+ (
+ typeof name !== "string" &&
+ typeof name !== (
+ // class decorators can have a `name` of `string | undefined`.
+ // all others can be `string | symbol`.
+ kind === "class" ? "undefined" : "symbol"
+ )
+ ) || (kind !== "class" && !(
+ "private" in context && typeof context.private === "boolean" &&
+ "static" in context && typeof context.static === "boolean" &&
+ "access" in context && typeof context.access === "object" &&
+ context.access != null && !Array.isArray(context.access)
+ ))
+ ) return false;
+ const { access = {} } = context as ClassMemberDecoratorContext;
+ return !(
+ typeof access === "object" && access != null &&
+ ("has" in access && typeof access.has === "function") &&
+ (typeof (access as any).get === (
+ ["accessor", "getter", "field", "method"].includes(kind) &&
+ "get" in access
+ ? "function"
+ : "undefined"
+ )) &&
+ (typeof (access as any).set === (
+ ["accessor", "setter", "field", "method"].includes(kind) &&
+ "set" in access
+ ? "function"
+ : "undefined"
+ ))
+ );
+ }
+ }
+ return false;
+}
+
+/**
+ * Checks if the provided target is a valid target for the given decorator
+ * context. This utility is useful for verifying that the target received by
+ * an overloaded stage 3 decorator function is compatible with the context
+ * object it receives as well.
+ *
+ * **Note**: this is only compatible with Stage 3 decorators, and will return
+ * `false` if used with legacy decorator arguments.
+ *
+ * @template {DecoratorContext} T The type of decorator context to check.
+ * @param target The target to check.
+ * @param context The context object to check against
+ * @returns {target is DecoratorArgsTypeMap[T["kind"]][0]} `true` if the target
+ * is valid for the given context, `false` otherwise.
+ * @category Utilities
+ */
+export function isValidTarget(
+ target: unknown,
+ context: T,
+): target is DecoratorArgsTypeMap[T["kind"]][0] {
+ if (isDecoratorContext(context)) {
+ switch (context.kind) {
+ case "field":
+ return typeof target === "undefined";
+ case "accessor":
+ return (
+ typeof target === "object" && !!target && !Array.isArray(target) &&
+ "get" in target && typeof target.get === "function" &&
+ "set" in target && typeof target.set === "function"
+ );
+ default:
+ return typeof target === "function";
+ }
+ }
+ return false;
+}
diff --git a/packages/types/legacy.ts b/packages/types/legacy.ts
new file mode 100644
index 0000000..f1e922c
--- /dev/null
+++ b/packages/types/legacy.ts
@@ -0,0 +1,31 @@
+/**
+ * @module legacy
+ *
+ * This module provides generic type definitions for the legacy Stage 2 form
+ * of TypeScript Decorators commonly used prior to TypeScript v5.0. It is not
+ * recommended to use these types in new code, as they have reached the end of
+ * their life cycle and are no longer being actively developed or maintained.
+ *
+ * Instead, use the new Stage 3 Decorators, which have their signatures
+ * defined in the `./signatures.ts` module. These new decorators are more
+ * powerful and flexible, much easier to use, and are under active development
+ * by both the TypeScript team and the community at large.
+ *
+ * Unfortunately, the Stage 3 form of the Decorators Proposal does not include
+ * support for a ParameterDecorator equivalent. Due to the popularity and the
+ * proliferation of ParameterDecorator usage in the wild, it's likely that
+ * many projects and libraries will continue to use the legacy Stage 2 form of
+ * the decorators for some time to come. As such, these types are provided for
+ * the benefit of those who are maintaining or updating existing code.
+ *
+ * @see https://github.com/tc39/proposal-decorators
+ * @see https://decorators.deno.dev for a living document on the Decorators
+ * API
+ */
+export * from "./legacy/accessor.ts";
+export * from "./legacy/class.ts";
+export * from "./legacy/guards.ts";
+export * from "./legacy/method.ts";
+export * from "./legacy/parameter.ts";
+export * from "./legacy/property.ts";
+export * from "./legacy/utilities.ts";
diff --git a/packages/types/legacy/accessor.ts b/packages/types/legacy/accessor.ts
new file mode 100644
index 0000000..03811e5
--- /dev/null
+++ b/packages/types/legacy/accessor.ts
@@ -0,0 +1,37 @@
+import type {
+ AbstractConstructor,
+ AccessorPropertyDescriptor,
+ KeyOf,
+} from "../_internal.ts";
+
+/**
+ * Represents a ClassFieldDecorator function in the legacy Stage 2 syntax.
+ *
+ * This type of decorator requires the compiler option
+ * `experimentalDecorators` be explicitly set to `true` in your
+ * `tsconfig.json` or `deno.json` file in TypeScript v5.0 and later. It is not
+ * recommended for use in new code.
+ *
+ * @template This The type of the class instance or constructor function.
+ * @template Value The type of the class field value.
+ * @template Key The type of the class field key.
+ * @category Legacy Decorators
+ * @module legacy:accessor
+ */
+export interface LegacyAccessorDecoratorFunction<
+ This extends object = object | AbstractConstructor,
+ // deno-lint-ignore no-explicit-any
+ Value = any,
+ Key extends KeyOf = KeyOf,
+> {
+ (
+ target: T,
+ key: K,
+ descriptor: AccessorPropertyDescriptor,
+ ): AccessorPropertyDescriptor;
+ (
+ target: This,
+ key: Key,
+ descriptor: AccessorPropertyDescriptor,
+ ): AccessorPropertyDescriptor;
+}
diff --git a/packages/types/legacy/class.ts b/packages/types/legacy/class.ts
new file mode 100644
index 0000000..f80eedc
--- /dev/null
+++ b/packages/types/legacy/class.ts
@@ -0,0 +1,21 @@
+import type { Constructor } from "../_internal.ts";
+
+/**
+ * Represents a ClassDecorator function in the legacy Stage 2 syntax.
+ *
+ * This type of decorator requires the compiler option
+ * `experimentalDecorators` be explicitly set to `true` in your
+ * `tsconfig.json` or `deno.json` file in TypeScript v5.0 and later. It is not
+ * recommended for use in new code.
+ *
+ * @template Class The type of the class instance or constructor function.
+ * @category Legacy Decorators
+ * @module legacy:class
+ */
+export interface LegacyClassDecoratorFunction<
+ Proto extends object = object,
+ Class extends Constructor = Constructor,
+ Return extends void | Class = void | Class,
+> {
+ (target: Class): Return;
+}
diff --git a/packages/types/legacy/guards.ts b/packages/types/legacy/guards.ts
new file mode 100644
index 0000000..94345e7
--- /dev/null
+++ b/packages/types/legacy/guards.ts
@@ -0,0 +1,88 @@
+import type { KeyOf } from "../_internal.ts";
+import type { LegacyDecoratorArguments } from "./utilities.ts";
+
+/**
+ * Checks if the provided arguments are compatible with a legacy decorator
+ * function, returning `true` if they are, and `false` if they are not.
+ *
+ * To check if the arguments are compatible with a Stage 3 Decorator function,
+ * see {@link isDecoratorArguments} instead.
+ *
+ * @template {readonly unknown[]} A The tuple of decorator arguments.
+ * @param args The tuple of decorator arguments to check.
+ * @returns {args is LegacyDecoratorArguments} `true` if the arguments are
+ * compatible with a legacy decorator function, `false` otherwise.
+ * @category Utilities
+ * @example
+ * ```ts
+ * import { isLegacyDecoratorArguments } from "@decorators/types";
+ *
+ * function decorator(...args: any[]) {
+ * if (isLegacyDecoratorArguments(args)) {
+ * // called as a legacy decorator with no args
+ * return decoratorLegacy(...args);
+ * } else {
+ * // called as a decorator factory with args
+ * return (target, key, descriptor) => decoratorLegacy(target, key, descriptor);
+ * }
+ * }
+ * ```
+ */
+export function isLegacyDecoratorArguments<
+ This,
+ Value,
+ Key extends KeyOf = KeyOf,
+>(args: unknown): args is LegacyDecoratorArguments;
+
+/**
+ * Checks if the provided arguments are compatible with a legacy decorator
+ * function, returning `true` if they are, and `false` if they are not.
+ *
+ * @template {readonly unknown[]} A The tuple of decorator arguments.
+ * @param args The tuple of decorator arguments to check.
+ * @returns {args is LegacyDecoratorArguments} `true` if the arguments are
+ * compatible with a legacy decorator function, `false` otherwise.
+ * @category Utilities
+ */
+export function isLegacyDecoratorArguments(
+ args: [...A],
+): args is [...Extract>];
+
+/** @ignore */
+export function isLegacyDecoratorArguments(
+ args: unknown,
+): args is LegacyDecoratorArguments {
+ if (Array.isArray(args) && args.length > 0 && args.length < 4) {
+ const [target, key, desc] = args;
+ // [target]
+ if (args.length === 1) return typeof target === "function";
+ if (args.length === 2 && typeof key === "object" && key != null) {
+ // fails fast if one of two args appears to be a context object
+ // (since that is stage 3 decorator syntax only)
+ return false;
+ }
+ return (
+ // [target, key?, desc?]
+ // argument 1 (target) must always be present, duh
+ target != null &&
+ // argument 2 (key) can be one of two types:
+ // - string or symbol (property key, descriptor is optional)
+ // - undefined (when targeting the class constructor function)
+ // -> the descriptor object must be present in this case!
+ (typeof key === "string" || typeof key === "symbol" ||
+ (key == null &&
+ (typeof target === "function" ||
+ typeof desc === "object" && desc != null))) &&
+ // argument 3 (descriptor) can be one of three types:
+ // - undefined (void, class decorators and property decorators)
+ // - a number (parameter index for ParameterDecorators)
+ // - PropertyDescriptor object (method / accessor decorators)
+ (desc == null || typeof desc === "number" || (
+ typeof desc === "object" && !Array.isArray(desc)
+ ))
+ );
+ }
+
+ // drop everything else like it's third period french
+ return false;
+}
diff --git a/packages/types/legacy/method.ts b/packages/types/legacy/method.ts
new file mode 100644
index 0000000..3e0bbbf
--- /dev/null
+++ b/packages/types/legacy/method.ts
@@ -0,0 +1,27 @@
+import type { AbstractConstructor, KeyOf } from "../_internal.ts";
+
+/**
+ * Represents a MethodDecorator function in the legacy Stage 2 syntax.
+ *
+ * This type of decorator requires the compiler option
+ * `experimentalDecorators` be explicitly set to `true` in your
+ * `tsconfig.json` or `deno.json` file in TypeScript v5.0 and later. It is not
+ * recommended for use in new code.
+ *
+ * @template This The type of the class instance or constructor function.
+ * @template Value The type of the class method's return value.
+ * @template Key The type of the class method key.
+ * @category Legacy Decorators
+ * @module legacy:method
+ */
+export interface LegacyMethodDecoratorFunction<
+ This extends object = object | AbstractConstructor,
+ Value = unknown,
+ Key extends KeyOf = KeyOf,
+> {
+ (
+ target: This,
+ key: Key,
+ descriptor: TypedPropertyDescriptor,
+ ): TypedPropertyDescriptor;
+}
diff --git a/packages/types/legacy/parameter.ts b/packages/types/legacy/parameter.ts
new file mode 100644
index 0000000..9d1e75b
--- /dev/null
+++ b/packages/types/legacy/parameter.ts
@@ -0,0 +1,21 @@
+import type { AbstractConstructor, FunctionKeys, KeyOf } from "../_internal.ts";
+
+/**
+ * Represents a ParameterDecorator function in the legacy Stage 2 syntax.
+ *
+ * This type of decorator requires the compiler option
+ * `experimentalDecorators` be explicitly set to `true` in your
+ * `tsconfig.json` or `deno.json` file in TypeScript v5.0 and later. It is not
+ * recommended for use in new code.
+ *
+ * @template Target The type of the class instance or constructor function.
+ * @template Key The type of the class method key.
+ * @category Legacy Decorators
+ * @module parameter
+ */
+export interface LegacyParameterDecoratorFunction<
+ Target extends object = object | AbstractConstructor,
+ Key extends KeyOf = FunctionKeys,
+> {
+ (target: Target, key: Key, parameterIndex: number): void;
+}
diff --git a/packages/types/legacy/property.ts b/packages/types/legacy/property.ts
new file mode 100644
index 0000000..90f86e1
--- /dev/null
+++ b/packages/types/legacy/property.ts
@@ -0,0 +1,21 @@
+import type { AbstractConstructor, KeyOf } from "../_internal.ts";
+
+/**
+ * Represents a PropertyDecorator function in the legacy Stage 2 syntax.
+ *
+ * This type of decorator requires the compiler option
+ * `experimentalDecorators` be explicitly set to `true` in your
+ * `tsconfig.json` or `deno.json` file in TypeScript v5.0 and later. It is not
+ * recommended for use in new code.
+ *
+ * @template This The type of the class instance or constructor function.
+ * @template Key The type of the class property key.
+ * @category Legacy Decorators
+ * @module legacy:property
+ */
+export interface LegacyPropertyDecoratorFunction<
+ This extends object = object | AbstractConstructor,
+ Key extends KeyOf = KeyOf,
+> {
+ (target: This, key: Key): void;
+}
diff --git a/packages/types/legacy/utilities.ts b/packages/types/legacy/utilities.ts
new file mode 100644
index 0000000..e6131f8
--- /dev/null
+++ b/packages/types/legacy/utilities.ts
@@ -0,0 +1,175 @@
+// deno-lint-ignore-file ban-types no-explicit-any
+
+import type {
+AbstractConstructor,
+ Is,
+ KeyOf,
+ LegacyDecoratorTypeMap,
+ MaybeVoidable,
+ ValueOf,
+} from "../_internal.ts";
+
+export type LegacyDecoratorKind = string & keyof LegacyDecoratorTypeMap;
+
+/**
+ * Represents a decorator with multiple overload signatures, configurable via
+ * the {@linkcode Kind} type parameter.
+ */
+export interface LegacyOverloadedDecoratorFunction<
+ Kind extends LegacyDecoratorKind = LegacyDecoratorKind,
+ Voidable extends boolean | void = true,
+> {
+ <
+ const Args extends Readonly<
+ Parameters[Kind]>
+ >,
+ This = LegacyDecoratorThis,
+ Value = LegacyDecoratorValue,
+ >(...args: Args): LegacyDecoratorReturn;
+}
+
+/**
+ * Represents all possible arguments that can be used in a legacy decorator
+ * function of any type.
+ * @category Arguments
+ */
+export type LegacyDecoratorArguments<
+ This = any,
+ Value = any,
+ Key extends KeyOf> = KeyOf>,
+> = Readonly>>>;
+
+/**
+ * Represents the signature of all the possible types of legacy (stage 2)
+ * experimental decorators. By using the type parameters on this utility type,
+ * you can specify the types of the `this` context, the target member's value
+ * being decorated as well as that member's key (if applicable).
+ *
+ * @template [This=unknown] The type of the `this` context for the decorator.
+ * @template [Value=unknown] The type of the target member being decorated.
+ * @template [Key=PropertyKey] The type of the key for the target member.
+ * @category Legacy Decorators
+ * @category Signatures
+ */
+export type LegacyDecoratorFunction<
+ This = unknown,
+ Value = unknown,
+ Key extends KeyOf> = KeyOf>,
+> = ValueOf>;
+
+/**
+ * Resolves the contextual `this` type for a legacy decorator function, based
+ * on arguments provided in the {@linkcode A} tuple. If the contextual `this`
+ * type cannot be resolved, the {@link Fallback} type (default: `unknown`) is
+ * returned instead.
+ *
+ * **Note**: this is specifically for legacy (stage 2) decorators, and is not
+ * capable of handling the arguments of Stage 3 decorators. To extract the
+ * `this` type from **_Stage 3_** arguments, see
+ * {@link DecoratorThis}.
+ *
+ * @template {readonly unknown[]} A The tuple of decorator arguments.
+ * @template [Fallback=unknown] Type to use if `this` cannot be resolved.
+ * @category Signatures (Legacy)
+ */
+// deno-fmt-ignore
+export type LegacyDecoratorThis =
+ | A extends readonly [infer V extends Function] ? V
+ : A extends readonly [infer T extends object, string | symbol | undefined] ? T
+ : A extends readonly [infer T extends object, string | symbol, PropertyDescriptor | void] ? T
+ : Fallback;
+
+/**
+ * Resolves the decorated member's value type for a legacy decorator function,
+ * based on arguments provided in the {@linkcode A} tuple. If the value type
+ * cannot be resolved, the {@linkcode Fallback} type (default: `unknown`) is
+ * returned instead. This utility is useful for inferring the type of the
+ * value being decorated by a legacy decorator.
+ *
+ * **Note**: this is specifically for legacy (stage 2) decorators, and is not
+ * capable of handling the arguments of Stage 3 decorators. To extract the
+ * value type from **_Stage 3_** arguments, see
+ * {@link DecoratorValue}.
+ *
+ * @template {readonly unknown[]} A The tuple of decorator arguments.
+ * @template [Fallback=unknown] Type to use if the value type cannot be
+ * resolved.
+ * @category Signatures (Legacy)
+ */
+// deno-fmt-ignore
+export type LegacyDecoratorValue =
+ | [A] extends [never] ? Fallback
+ : [A] extends readonly [[infer V extends AbstractConstructor]] ? V
+ : [A] extends readonly [[any, string | symbol | undefined, TypedPropertyDescriptor]] ? V
+ : [A] extends readonly [[infer T, infer K extends string | symbol | undefined, ...([number | PropertyDescriptor | void | undefined] | [])]]
+ ? [K] extends [keyof T] ? T[K]
+ : [A[2]] extends [TypedPropertyDescriptor] ? V
+ : Fallback
+ : [A] extends readonly [[infer T, infer K extends string | symbol]]
+ ? [K] extends [keyof T] ? T[K] : Fallback
+ : Fallback;
+
+/**
+ * Determines the return type of a legacy decorator function.
+ *
+ * @template A The tuple of decorator arguments.
+ * @template Voidable If set to true, return types will include the `void`
+ * union member. If false, the `void` member will be excluded. Default is
+ * `true`.
+ * @category Signatures
+ * @example
+ * ```ts
+ * import type {
+ * LegacyDecoratorReturn,
+ * LegacyClassDecoratorFunction,
+ * } from "@decorators/types";
+ *
+ * class FoobarClass {}
+ *
+ * type MyLegacyDecoratorReturn = LegacyDecoratorReturn<
+ * Parameters>
+ * >; // => void | typeof FoobarClass
+ * ```
+ */
+// deno-fmt-ignore
+export type LegacyDecoratorReturn<
+ A extends readonly unknown[],
+ Voidable extends boolean | void = true,
+ Fallback = unknown,
+> = A extends readonly [infer Class extends abstract new (...args: any) => any]
+ ? MaybeVoidable
+ : A extends readonly [
+ any,
+ string | symbol | undefined,
+ TypedPropertyDescriptor | void
+ ] ? MaybeVoidable, Voidable>
+ : A extends (
+ | readonly [any, string | symbol | undefined, number]
+ | readonly [any, string | symbol]
+ ) ? void
+ : Fallback;
+
+/**
+ * Resolves the key of the decorated member for a legacy decorator function,
+ * based on arguments provided in the {@linkcode A} tuple. If the key cannot
+ * be resolved, the {@linkcode Fallback} type (default: `string | symbol |
+ * undefined`) is returned instead. This utility is useful for inferring the
+ * property key of the class member, or the name of the class itself in the
+ * case of a ClassDecoratorFunction, that is being decorated with a legacy decorator.
+ *
+ * **Note**: this is specifically for legacy (stage 2) decorators, and is not
+ * capable of handling the arguments of Stage 3 decorators. To extract the key
+ * from **_Stage 3_** arguments, see {@link DecoratorName}.
+ *
+ * @template {readonly unknown[]} A The tuple of decorator arguments.
+ * @template [Fallback=string | symbol | undefined] Type to use if the key
+ * cannot be resolved.
+ * @category Signatures (Legacy)
+ */
+// deno-fmt-ignore
+export type LegacyDecoratorName =
+ | A extends readonly [any, string | symbol] ? A[1]
+ : A extends readonly [any, string | symbol | undefined, PropertyDescriptor] ? A[1]
+ : A extends readonly [any, string | symbol, number] ? A[1]
+ : A[0] extends { name: infer N extends string | undefined } ? N
+ : Fallback;
diff --git a/packages/types/method.ts b/packages/types/method.ts
new file mode 100644
index 0000000..586eac8
--- /dev/null
+++ b/packages/types/method.ts
@@ -0,0 +1,106 @@
+/**
+ * @module method
+ *
+ * This module provides types for working with method decorators according to
+ * the latest version of the TC39 Decorators Proposal (now at Stage 3).
+ *
+ * The types in this module provide a structured and well-documented
+ * foundation for creating consistent method decorators with easily
+ * predictable behavior.
+ *
+ * @example
+ * ```ts
+ * import type { ClassMethod, ClassMethodDecoratorFunction } from "@decorators/types/method";
+ *
+ * const bind = >(): ClassMethodDecoratorFunction =>
+ * (target, context) => {
+ * context.addInitializer(function() {
+ * this[context.name] = this[context.name].bind(this);
+ * });
+ * };
+ *
+ * class Example {
+ * #field = "value";
+ *
+ * @bind() method() { return this.#field;
+ * }
+ * }
+ *
+ * const example = new Example(); const method = example.method;
+ *
+ * console.log(method()); // logs "value"
+ * ```
+ * @category Method Decorators
+ */
+
+/**
+ * Represents a method on a class that is being decorated, whether its static
+ * or an instance method, public or private.
+ *
+ * @template [This=unknown] The type on which the class element will be
+ * defined. For a static class element, this is the type of the constructor.
+ * For non-static class elements, this will be the type of the instance.
+ * @template [Args=any[]] The type of the method's arguments.
+ * @template [Return=unknown] The type of the method's return value.
+ * @category Method Decorators
+ */
+export interface ClassMethod<
+ This = unknown,
+ // deno-lint-ignore no-explicit-any
+ Args extends readonly unknown[] = any[],
+ Return = unknown,
+> {
+ (this: This, ...args: Args): Return;
+}
+
+/**
+ * Represents the decorator signature applied to a class method.
+ *
+ * ### Target Argument
+ *
+ * The `target` argument is the method itself, and is a function that receives
+ * the same arguments as the method, and returns the same value as the method.
+ *
+ * ### Context Argument
+ *
+ * The `context` argument is a {@linkcode ClassMethodDecoratorContext} object
+ * containing the metadata and other information about the method being
+ * decorated. It's `kind` property will always be `"method"`.
+ *
+ * Similar to the other decorator types, it also includes an `addInitializer`
+ * method, `name` and `metadata` properties. And like all class member
+ * decorators, it also has `access`, `static`, and `private` properties.
+ *
+ * ### Return Value
+ *
+ * The return value of a method decorator may either be `void` (if no changes
+ * are needed), or a new function to replace the one being decorated.
+ *
+ * @template [This=unknown] The type on which the class element will be
+ * defined. For a static class element, this is the type of the constructor.
+ * For non-static class elements, this will be the type of the instance.
+ * @template [Value=ClassMethod] The type of the class method.
+ * @template [Return=void|Value] The return type of the method decorator. For
+ * decorators that return a new, replacement method, the return type will be
+ * the same as the method being decorated (since they must maintain the same
+ * signature). For decorators that do not return a value, this will be `void`.
+ * Defaults to `void | Value`, meaning both of those scenarios are allowed.
+ * @category Method Decorators
+ */
+export interface ClassMethodDecoratorFunction<
+ This = unknown,
+ Value extends ClassMethod = ClassMethod,
+ Return extends void | Value = void | Value,
+> {
+ /**
+ * @param target The method itself.
+ * @param context The context object for the method decorator.
+ * @returns Either `void` or a new method function to replace the original.
+ * The type of the returned value is controlled by the `Return` type param
+ * on the {@link ClassMethodDecoratorFunction} interface.
+ */
+ (
+ target: Value,
+ context: ClassMethodDecoratorContext,
+ ): Return;
+}
diff --git a/packages/types/mod.ts b/packages/types/mod.ts
new file mode 100644
index 0000000..d29d417
--- /dev/null
+++ b/packages/types/mod.ts
@@ -0,0 +1,69 @@
+/**
+ * @module types
+ *
+ * The `@decorators/types` package provides a collection of utility types and
+ * runtime type guards for working with both modern and legacy decorators in a
+ * TypeScript codebase. These types are designed to simplify the creation, use,
+ * testing, and maintenance of decorators and decorator factories by providing
+ * a consistent, well-documented, and type-safe foundation for their respective
+ * API surfaces.
+ *
+ * An immediate use case for these types is to minimalize boilerplate code
+ * required to define decorators that are cross-compatible with both the legacy
+ * and stage 3 forms of the Decorators Proposal, as well as creating decorators
+ * that are usable on multiple targets (e.g., classes, methods, fields, etc.).
+ *
+ * Such a task would typically involve creating a decorator factory that
+ * returned a decorator with a specific signature for each of the supported
+ * target types. This could quickly become cumbersome and error-prone without
+ * some outside help; but with a package like `@decorators/types`, the process
+ * suddenly becomes much more manageable:
+ *
+ * ```ts
+ * import {
+ * isDecoratorArguments,
+ * isLegacyDecoratorArguments,
+ * type AnyDecoratorArguments,
+ * type AnyDecoratorReturn,
+ * } from "@decorators/types";
+ *
+ * const log = >(
+ * prefix?: string
+ * ): (...args: [...Args]) => AnyDecoratorReturn => {
+ * return (...args) => {
+ * if (isDecoratorArguments(args)) {
+ * // Stage 3 Decorators implementation ...
+ * // args -> [target, context]
+ * console.log(`[${prefix}] Initializing ${String(args[1].name?.toString())}`);
+ * } else if (isLegacyDecoratorArguments(args)) {
+ * // Legacy Decorators implementation ...
+ * // args -> [target, key, descriptor?]
+ * console.log(`[${prefix}] Initializing ${String(args[1].toString())}`);
+ * } else {
+ * throw new TypeError("Invalid decorator arguments");
+ * }
+ * };
+ * };
+ *
+ * // the `log` decorator can now be used on any target type, in both
+ * // legacy and stage 3 environments, with full type safety and consistency:
+ *
+ * @log("class") class Example {
+ * // ...
+ *
+ * @log("method") method() { return "foo" }
+ *
+ * @log("getter") get field() { return 42 }
+ * }
+ * ```
+ */
+export * from "./accessor.ts";
+export * from "./class.ts";
+export * from "./field.ts";
+export * from "./getter.ts";
+export * from "./guards.ts";
+export * from "./legacy.ts";
+export * from "./method.ts";
+export * from "./setter.ts";
+export * from "./signatures.ts";
+export * from "./utilities.ts";
diff --git a/packages/types/setter.ts b/packages/types/setter.ts
new file mode 100644
index 0000000..4d0ce85
--- /dev/null
+++ b/packages/types/setter.ts
@@ -0,0 +1,97 @@
+/**
+ * @module setter
+ *
+ * This module provides types for working with class setter decorators according
+ * to the latest version of the TC39 Decorators Proposal (now at Stage 3).
+ *
+ * The types in this module provide a structured and well-documented foundation
+ * for creating consistent setter decorators with easily predictable behavior.
+ *
+ * @example
+ * ```ts
+ * import type { ClassSetterDecoratorFunction } from "@decorators/types/setter";
+ *
+ * const log = (): ClassSetterDecoratorFunction =>
+ * (target, context) => {
+ * return function (newValue) {
+ * console.log(`Setting ${String(context.name)} to ${newValue}`);
+ * target.call(this, newValue);
+ * };
+ * };
+ *
+ * class Example {
+ * #field = "value";
+ *
+ * @log() set field(newValue: string) {
+ * this.#field = newValue;
+ * }
+ * }
+ *
+ * const example = new Example();
+ *
+ * example.field = "new value"; // logs "Setting field to new value"
+ * ```
+ * @category Setter Decorators
+ */
+
+/**
+ * Represents a setter method on a class that is being decorated, regardless
+ * of whether its static/instance and public/private.
+ *
+ * @template [This=unknown] The type on which the class element will be defined. For a
+ * static class element, this is the type of the constructor. For non-static
+ * class elements, this will be the type of the instance.
+ * @template [Value=unknown] The type of the setter's argument.
+ * @category Setter Decorators
+ */
+export interface ClassSetter {
+ (this: This, newValue: Value): void;
+}
+
+/**
+ * Represents the decorator signature applied to a class setter member.
+ *
+ * #### What are setters?
+ *
+ * A setter is a special type of method that is used to write the value of a
+ * property. It is defined using the `set` keyword, followed by an identifier
+ * and a block of code that sets the value of the property.
+ *
+ * #### Param: `target`
+ *
+ * The `target` argument is the setter method itself, and is a function that
+ * receives the new value of the property as its only argument.
+ *
+ * #### Param: `context`
+ *
+ * The `context` argument is a {@linkcode ClassSetterDecoratorContext} object
+ * containing the metadata and other information about the setter being
+ * decorated. It's `kind` property will always be `"setter"`.
+ *
+ * Similar to the other decorator types, it also includes an `addInitializer`
+ * method, `name` and `metadata` properties. And like all class member
+ * decorators, it also has `access`, `static`, and `private` properties.
+ *
+ * #### Returned Value
+ *
+ * The return value of a setter decorator may either be `void` (if no changes
+ * are needed), or a new setter function to replace the original setter.
+ *
+ * @template This The type on which the class element will be defined. For a
+ * static class element, this is the type of the constructor. For non-static
+ * class elements, this will be the type of the instance.
+ * @template Value The type of the class setter's expected value.
+ * @category Setter Decorators
+ */
+export interface ClassSetterDecoratorFunction<
+ This = unknown,
+ Value = unknown,
+ Return extends void | ClassSetter =
+ | void
+ | ClassSetter,
+> {
+ (
+ target: ClassSetter,
+ context: ClassSetterDecoratorContext,
+ ): Return;
+}
diff --git a/packages/types/signatures.ts b/packages/types/signatures.ts
new file mode 100644
index 0000000..f2f74b9
--- /dev/null
+++ b/packages/types/signatures.ts
@@ -0,0 +1,241 @@
+// deno-lint-ignore-file no-explicit-any
+import { __throw } from "./_internal.ts";
+import type {
+ AnyDecoratorTypeMap,
+ Constructor,
+ DecoratorTypeMap,
+ Is,
+ LegacyDecoratorTypeMap,
+ ValueOf,
+ VoidableArgument,
+} from "./_internal.ts";
+import type { ClassDecoratorFunction } from "./class.ts";
+import type { ClassFieldDecoratorFunction } from "./field.ts";
+import type { ClassAccessorDecoratorFunction } from "./accessor.ts";
+import type { ClassMethod, ClassMethodDecoratorFunction } from "./method.ts";
+import type { ClassGetterDecoratorFunction } from "./getter.ts";
+import type { ClassSetterDecoratorFunction } from "./setter.ts";
+import type {
+ AnyDecoratorArguments,
+ AnyDecoratorReturn,
+ AnyDecoratorThis,
+ AnyDecoratorValue,
+ DecoratorArguments,
+ DecoratorReturn,
+ DecoratorThis,
+ DecoratorValue,
+} from "./utilities.ts";
+import {
+ LegacyDecoratorArguments,
+ LegacyDecoratorKind,
+ LegacyDecoratorReturn,
+ LegacyDecoratorThis,
+ LegacyDecoratorValue,
+} from "./legacy.ts";
+
+/**
+ * Represents any of the possible types of decorators that can be applied to a
+ * class or to class members. This is a union of all the other decorator
+ * types.
+ *
+ * @template [This=unknown] The type on which the class element will be
+ * defined. For a static class element, this is the type of the constructor.
+ * For non-static class elements, this will be the type of the instance.
+ * @template [Value=unknown] The type of the class member being decorated.
+ * @category Decorators
+ * @category Signatures
+ */
+export type DecoratorFunction =
+ // coerce to AbstractConstructor to satisfy the type constraint
+ | ClassDecoratorFunction<
+ InstanceType>,
+ Is
+ >
+ // coerce to ClassMethod to satisfy the type constraint
+ | ClassFieldDecoratorFunction
+ | ClassAccessorDecoratorFunction
+ | ClassGetterDecoratorFunction
+ | ClassSetterDecoratorFunction
+ | ClassMethodDecoratorFunction>>;
+
+/**
+ * Represents the "kind" of all possible Stage 3 Decorator types. This is used
+ * to differentiate between the different types of decorators based on the
+ * `kind` property of the context object.
+ * @category Signatures
+ */
+export type DecoratorKind = string & keyof DecoratorTypeMap;
+
+/**
+ * Represents the "kind" of all possible decorators, both legacy and stage 3.
+ * For Stage 3 decorators, the kind is derived from the `kind` property of the
+ * context object. For Legacy decorators, which do not have a context object,
+ * it is derived from the decorator's signature using the internal type map
+ * `LegacyDecoratorTypeMap`.
+ * @category Signatures
+ */
+export type AnyDecoratorKind = string & keyof AnyDecoratorTypeMap;
+
+/**
+ * Represents the signature of all the possible types of decorators that can
+ * be applied to a class or to class members. This is a union of all the other
+ * decorator types, including legacy decorators.
+ *
+ * @template [This=unknown] The type on which the class element will be
+ * defined. For a static class element, this is the type of the constructor.
+ * For non-static class elements, this will be the type of the instance.
+ * @template [Value=unknown] The type of the class member being decorated.
+ * @category Decorators
+ * @category Signatures
+ */
+export type AnyDecoratorFunction<
+ This = unknown,
+ Value = unknown,
+> = ValueOf>;
+
+/**
+ * Represents a decorator with multiple overload signatures, configurable via
+ * the {@linkcode Kind} type parameter.
+ */
+export interface OverloadedDecoratorFunction<
+ Kind extends DecoratorKind = DecoratorKind,
+ Void extends VoidableArgument = true,
+> {
+ <
+ Args extends Parameters[Kind]>,
+ This = AnyDecoratorThis,
+ Value = AnyDecoratorValue,
+ >(...args: Args): DecoratorReturn;
+}
+
+/**
+ * Represents a decorator with multiple overload signatures, configurable via
+ * the {@linkcode Kind} type parameter.
+ */
+export interface AnyOverloadedDecoratorFunction<
+ Kind extends AnyDecoratorKind = AnyDecoratorKind,
+ Void extends VoidableArgument = true,
+> {
+ <
+ Args extends Parameters[Kind]>,
+ This = AnyDecoratorThis,
+ Value = AnyDecoratorValue,
+ >(...args: Args): AnyDecoratorReturn;
+}
+
+export interface DecoratorFactory<
+ Outer extends readonly unknown[] = readonly any[],
+ Void extends VoidableArgument = true,
+> {
+ <
+ Inner extends DecoratorArguments,
+ This = DecoratorThis,
+ Value = DecoratorValue,
+ >(...outer: Outer): (...inner: Inner) => DecoratorReturn;
+}
+
+export interface LegacyDecoratorFactory<
+ Outer extends readonly unknown[] = readonly any[],
+ Void extends VoidableArgument = true,
+> {
+ <
+ Inner extends LegacyDecoratorArguments,
+ This = LegacyDecoratorThis,
+ Value = LegacyDecoratorValue,
+ >(...outer: Outer): (...inner: Inner) => LegacyDecoratorReturn;
+}
+
+export interface AnyDecoratorFactory<
+ Outer extends readonly unknown[] = readonly any[],
+ Void extends VoidableArgument = true,
+> {
+ <
+ Inner extends AnyDecoratorArguments,
+ This = AnyDecoratorThis,
+ Value = AnyDecoratorValue,
+ >(...outer: Outer): (...inner: Inner) => AnyDecoratorReturn;
+}
+
+/**
+ * Represents a factory function that creates a new decorator function with
+ * the specified arguments. This is used to create decorator functions that
+ * require additional arguments to be passed to them.
+ *
+ * @template [Args=any[]] The type of the additional arguments to be passed to
+ * the decorator.
+ * @category Decorators
+ * @category Signatures
+ */
+export interface OverloadedDecoratorFactory<
+ Outer extends readonly unknown[] = readonly any[],
+ Kind extends DecoratorKind = DecoratorKind,
+ Void extends VoidableArgument = true,
+> {
+ /**
+ * @template [This=unknown] The type on which the class element will be
+ * defined. For a static class element, this is the type of the constructor.
+ * For non-static class elements, this will be the type of the instance.
+ * @template [Value=unknown] The type of the class member being decorated.
+ */
+ <
+ Inner extends Parameters[Kind]>,
+ This = DecoratorThis,
+ Value = DecoratorValue,
+ >(...outer: Outer): (...inner: Inner) => DecoratorReturn;
+}
+
+/**
+ * Represents a factory function that creates a new decorator function with
+ * the specified arguments. This is used to create decorator functions that
+ * require additional arguments to be passed to them.
+ *
+ * @template [Args=any[]] The type of the additional arguments to be passed to
+ * the decorator.
+ * @category Decorators
+ * @category Signatures
+ */
+export interface LegacyOverloadedDecoratorFactory<
+ Outer extends readonly unknown[] = readonly any[],
+ Kind extends LegacyDecoratorKind = LegacyDecoratorKind,
+ Void extends VoidableArgument = true,
+> {
+ /**
+ * @template [This=unknown] The type on which the class element will be
+ * defined. For a static class element, this is the type of the constructor.
+ * For non-static class elements, this will be the type of the instance.
+ * @template [Value=unknown] The type of the class member being decorated.
+ */
+ <
+ Inner extends Parameters[Kind]>,
+ This = LegacyDecoratorThis,
+ Value = LegacyDecoratorValue,
+ >(...outer: Outer): (...inner: Inner) => LegacyDecoratorReturn;
+}
+
+/**
+ * Represents a factory function that creates a new decorator function with
+ * the specified arguments. This is used to create decorator functions that
+ * require additional arguments to be passed to them.
+ *
+ * @template [Args=any[]] The type of the additional arguments to be passed to
+ * the decorator.
+ * @category Decorators
+ * @category Signatures
+ */
+export interface AnyOverloadedDecoratorFactory<
+ Outer extends readonly unknown[] = readonly any[],
+ Kind extends AnyDecoratorKind = AnyDecoratorKind,
+ Void extends VoidableArgument = true,
+> {
+ /**
+ * @template [This=unknown] The type on which the class element will be
+ * defined. For a static class element, this is the type of the constructor.
+ * For non-static class elements, this will be the type of the instance.
+ * @template [Value=unknown] The type of the class member being decorated.
+ */
+ <
+ Inner extends Parameters[Kind]>,
+ This = AnyDecoratorThis,
+ Value = AnyDecoratorValue,
+ >(...outer: Outer): (...inner: Inner) => AnyDecoratorReturn;
+}
diff --git a/packages/types/utilities.ts b/packages/types/utilities.ts
new file mode 100644
index 0000000..192520c
--- /dev/null
+++ b/packages/types/utilities.ts
@@ -0,0 +1,277 @@
+// deno-lint-ignore-file no-explicit-any
+
+import { __throw } from "./_internal.ts";
+import type {
+ AbstractConstructor,
+ DecoratorTypeMap,
+ MaybeVoidable,
+ Or,
+ ValueOf,
+ VoidableArgument,
+} from "./_internal.ts";
+import type { ClassFieldDecoratorResult } from "./field.ts";
+import type { ClassMethod } from "./method.ts";
+import type { ClassGetter } from "./getter.ts";
+import type { ClassSetter } from "./setter.ts";
+import type {
+ LegacyDecoratorArguments,
+ LegacyDecoratorName,
+ LegacyDecoratorReturn,
+ LegacyDecoratorThis,
+ LegacyDecoratorValue,
+} from "./legacy/utilities.ts";
+
+/**
+ * Represents all possible arguments that can be used in decorator of any
+ * type.
+ * @category Signatures
+ */
+export type DecoratorArguments<
+ This = object,
+ Value = unknown,
+> = Readonly>>>;
+
+/**
+ * Represents all possible arguments that can be passed to a decorator
+ * function or a legacy decorator function.
+ * @category Signatures
+ */
+export type AnyDecoratorArguments<
+ This = object,
+ Value = unknown,
+> =
+ | DecoratorArguments
+ | LegacyDecoratorArguments;
+
+/**
+ * Resolves the contextual `this` type for a decorator function, based on
+ * arguments provided in the {@linkcode A} tuple. If the contextual `this`
+ * type cannot be resolved, the {@linkcode Fallback} type (default: `unknown`)
+ * is returned instead. This utility is useful for inferring the type of the
+ * `this` context for a decorator function.
+ *
+ * **Note**: this is specifically for Stage 3 decorators, and is not capable
+ * of handling the arguments of legacy decorator functions. To extract the
+ * `this` type from **_legacy_** arguments, see
+ * {@link LegacyDecoratorThis}.
+ *
+ * @template {readonly unknown[]} A The tuple of decorator arguments.
+ * @template [Fallback=unknown] Type to use if `this` cannot be resolved.
+ * @category Signatures
+ */
+// deno-fmt-ignore
+export type DecoratorThis =
+ | A extends readonly [infer _, infer T extends object]
+ ? T extends ClassDecoratorContext any> ? C
+ : T extends ClassAccessorDecoratorContext ? This
+ : T extends ClassFieldDecoratorContext ? This
+ : T extends ClassGetterDecoratorContext ? This
+ : T extends ClassMethodDecoratorContext ? This
+ : T extends ClassSetterDecoratorContext ? This
+ : Fallback
+ : Fallback;
+
+/**
+ * Resolves the contextual `this` type for a decorator function, based on
+ * arguments provided in the {@linkcode A} tuple. If the contextual `this`
+ * type cannot be resolved, the {@linkcode Fallback} type (default: `unknown`)
+ * is returned instead. This utility is useful for inferring the type of the
+ * `this` context for a decorator (or legacy decorator) function that accepts
+ * multiple types of overloaded arguments.
+ *
+ * @template {readonly unknown[]} A The tuple of decorator arguments.
+ * @template [Fallback=unknown] Type to use if `this` cannot be resolved.
+ * @category Signatures
+ */
+export type AnyDecoratorThis<
+ A extends readonly unknown[],
+ Fallback = unknown,
+> = Or, Or, Fallback>>;
+
+/**
+ * Resolves the decorated member's value type for a stage 3 decorator
+ * function, based on arguments provided in the {@linkcode A} tuple. If the
+ * value type cannot be resolved, the {@linkcode Fallback} type (default:
+ * `unknown`) is returned instead.
+ *
+ * **Note**: this is specifically for Stage 3 decorators, and is not capable
+ * of handling the arguments of legacy decorator functions. To extract the
+ * value type from **_legacy_** arguments, see
+ * {@link LegacyDecoratorValue}.
+ *
+ * @template {readonly unknown[]} A The tuple of decorator arguments.
+ * @template [Fallback=unknown] Type to use if the value type cannot be
+ * resolved.
+ * @category Signatures
+ */
+// deno-fmt-ignore
+export type DecoratorValue =
+ | A extends readonly [unknown, infer T extends object] // [infer B, infer T]
+ ? T extends ClassDecoratorContext any> ? C
+ : T extends ClassAccessorDecoratorContext ? V
+ : T extends ClassFieldDecoratorContext ? V
+ : T extends ClassGetterDecoratorContext ? V
+ : T extends ClassSetterDecoratorContext ? V
+ : T extends ClassMethodDecoratorContext ? V
+ : Fallback
+ : Fallback;
+
+/**
+ * Resolves the decorated member's value type for a decorator function, based
+ * on arguments provided in the {@linkcode A} tuple. If the value type cannot
+ * be resolved, the {@linkcode Fallback} type (default: `unknown`) is returned
+ * instead. This utility is useful for inferring the type of the value being
+ * decorated by a decorator.
+ *
+ * @template {readonly unknown[]} A The tuple of decorator arguments.
+ * @template [Fallback=unknown] Type to use if the value type cannot be
+ * resolved.
+ * @category Signatures
+ */
+// deno-fmt-ignore
+export type AnyDecoratorValue =
+ (
+ | DecoratorValue
+ | LegacyDecoratorValue
+ ) extends infer V ? [V] extends [never] ? Fallback : V : Fallback;
+
+/**
+ * Resolves the key of the decorated member for a decorator function, based on
+ * arguments provided in the {@linkcode A} tuple. If the key cannot be
+ * resolved, the {@linkcode Fallback} type (default: `string | symbol |
+ * undefined`) is returned instead. This utility is useful for inferring the
+ * property key of the class member, or the name of the class itself in the
+ * case of a ClassDecoratorFunction, that is being decorated with a decorator.
+ *
+ * @template {readonly unknown[]} A The tuple of decorator arguments.
+ * @template [Fallback=string | symbol | undefined] Type to use if the key
+ * cannot be resolved.
+ * @category Signatures
+ */
+// deno-fmt-ignore
+export type DecoratorName =
+ | A extends readonly [any, { name: infer N extends string | symbol }] ? N
+ : A extends readonly [any, { name: infer N extends string | undefined }] ? N
+ : A extends readonly [any, { name: string | symbol | undefined }] ? A[1]["name"]
+ : Fallback;
+
+/**
+ * Resolves the key of the decorated member for a decorator function, based on
+ * arguments provided in the {@linkcode A} tuple. If the key cannot be resolved,
+ * the {@linkcode Fallback} type (default: `string | symbol | undefined`) is
+ * returned instead. This utility is useful for inferring the property key of
+ * the class member, or the name of the class itself in the case of a ClassDecoratorFunction,
+ * that is being decorated with a decorator.
+ * @template {readonly unknown[]} A The tuple of decorator arguments.
+ * @template [Fallback=string | symbol | undefined] Type to use if the key cannot be resolved.
+ * @category Signatures
+ */
+export type AnyDecoratorName<
+ A extends readonly unknown[],
+ Fallback = string | symbol | undefined,
+> = (
+ | DecoratorName
+ | LegacyDecoratorName
+) extends infer V ? [V] extends [never] ? Fallback : V : Fallback;
+
+/**
+ * Represents the return type of a decorator function.
+ *
+ * @template A The tuple of decorator arguments.
+ * @template Void Controls the decorator return type, allowing for the
+ * inclusion or exclusion of the `void` type. If set to `true`, return types
+ * will include the `void` union member. If false, the `void` member will be
+ * excluded. If set to `void`, the return type will be `void`. Default: `true`.
+ * @category Signatures
+ * @example
+ * ```ts
+ * import type {
+ * DecoratorReturn,
+ * ClassMethodDecoratorFunction,
+ * } from "@decorators/types";
+ *
+ * type MyDecoratorReturn1 = DecoratorReturn<
+ * Parameters>
+ * >; // => void | ((this: unknown, ...args: any[]) => unknown)
+ *
+ * type MyDecoratorReturn2 = DecoratorReturn<
+ * Parameters>,
+ * false, // exclude void from return types
+ * >; // => (this: unknown, ...args: any[]) => unknown
+ *
+ * type MyDecoratorReturn3 = DecoratorReturn<
+ * Parameters>,
+ * void, // only include void in return types
+ * >; // => void
+ * ```
+ * @example
+ * ```ts
+ * import type {
+ * DecoratorReturn,
+ * LegacyClassDecoratorFunction,
+ * } from "@decorators/types";
+ *
+ * class FoobarClass {}
+ *
+ * type MyLegacyDecoratorReturn = DecoratorReturn<
+ * Parameters>
+ * >; // => void | typeof FoobarClass
+ *
+ * type MyLegacyDecoratorReturn2 = DecoratorReturn<
+ * Parameters>,
+ * true, // enable legacy fallback
+ * false, // exclude void from return types
+ * >; // => typeof FoobarClass
+ * ```
+ */
+// deno-fmt-ignore
+export type DecoratorReturn<
+ A extends readonly unknown[],
+ Void extends VoidableArgument = true,
+ Fallback = unknown,
+> =
+ | [A] extends [[any, ClassMethodDecoratorContext]]
+ ? [Value] extends [(this: This, ...args: infer Args) => infer Return]
+ ? MaybeVoidable, Void>
+ : Fallback
+ : [A] extends [[any, ClassGetterDecoratorContext]]
+ ? MaybeVoidable, Void>
+ : [A] extends [[any, ClassSetterDecoratorContext]]
+ ? MaybeVoidable, Void>
+ : [A] extends [[any, ClassAccessorDecoratorContext]]
+ ? MaybeVoidable, Void>
+ : [A] extends [[undefined, ClassFieldDecoratorContext]]
+ ? MaybeVoidable, Void>
+ : [A] extends [
+ [AbstractConstructor, ClassDecoratorContext any>]
+ ] ? MaybeVoidable
+ : Fallback;
+
+/**
+ * Determines the return type of a given decorator function based on arguments
+ * it receives. This utility is useful for inferring the return type of a
+ * decorator function that accepts multiple decorator types.
+ *
+ * @template {readonly unknown[]} A The tuple of decorator arguments.
+ * @template [Void=true] If set to true, return types will include the
+ * `void` union member. If false, the `void` member will be excluded. If
+ * `void`, **only** `void` is included in the return type. Default is `true`.
+ * @template [Fallback=unknown] Type to use if the return type cannot be found.
+ * @category Signatures
+ */
+// deno-fmt-ignore
+export type AnyDecoratorReturn<
+ A extends readonly unknown[],
+ Void extends VoidableArgument = true,
+ Fallback = unknown,
+> = (
+ | LegacyDecoratorReturn
+ | DecoratorReturn
+) extends infer V ? [V] extends [never] ? Fallback : V : Fallback;
+
+export type {
+ LegacyDecoratorName,
+ LegacyDecoratorReturn,
+ LegacyDecoratorThis,
+ LegacyDecoratorValue,
+};