diff --git a/.eslintrc.base.cjs b/.eslintrc.base.cjs index 9621c394..74a8e084 100644 --- a/.eslintrc.base.cjs +++ b/.eslintrc.base.cjs @@ -845,6 +845,7 @@ const config = { '@typescript-eslint/consistent-indexed-object-style': 0, '@typescript-eslint/no-base-to-string': 0, '@typescript-eslint/no-empty-function': 0, + '@typescript-eslint/no-invalid-void-type': 0, '@typescript-eslint/no-unused-expressions': 0, '@typescript-eslint/prefer-ts-expect-error': 0, '@typescript-eslint/require-await': 0, diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 5f78cdda..18a9b46f 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -28,6 +28,12 @@ const config = { '@typescript-eslint/ban-types': 0 } }, + { + files: ['src/types/decorator-class.ts', 'src/types/decorator-method.ts'], + rules: { + '@typescript-eslint/no-invalid-void-type': 0 + } + }, { files: ['src/utils/__tests__/ksort.spec.ts'], rules: { diff --git a/src/interfaces/property-descriptor.ts b/src/interfaces/property-descriptor.ts index bac0dfe4..9a133aee 100644 --- a/src/interfaces/property-descriptor.ts +++ b/src/interfaces/property-descriptor.ts @@ -52,10 +52,10 @@ interface PropertyDescriptor { * being assigned to the property) and with `this` set to the object through * which the property is assigned. * - * @param {T} v - Value being assigned to property + * @param {T} value - Value being assigned to property * @return {void} Nothing when complete */ - set?(v: T): void + set?(value: T): void /** * Value associated with the property. diff --git a/src/types/__tests__/decorator-class.spec-d.ts b/src/types/__tests__/decorator-class.spec-d.ts new file mode 100644 index 00000000..ff3f6554 --- /dev/null +++ b/src/types/__tests__/decorator-class.spec-d.ts @@ -0,0 +1,20 @@ +/** + * @file Type Tests - ClassDecorator + * @module tutils/types/tests/unit-d/ClassDecorator + */ + +import type Vehicle from '#fixtures/types/vehicle' +import type Class from '../class' +import type TestSubject from '../decorator-class' + +describe('unit-d:types/ClassDecorator', () => { + type T = Class + + it('should be callable with [T]', () => { + expectTypeOf>().parameters.toEqualTypeOf<[T]>() + }) + + it('should return T | void', () => { + expectTypeOf>().returns.toEqualTypeOf() + }) +}) diff --git a/src/types/__tests__/decorator-method.spec-d.ts b/src/types/__tests__/decorator-method.spec-d.ts new file mode 100644 index 00000000..b4eecb99 --- /dev/null +++ b/src/types/__tests__/decorator-method.spec-d.ts @@ -0,0 +1,32 @@ +/** + * @file Type Tests - MethodDecorator + * @module tutils/types/tests/unit-d/MethodDecorator + */ + +import type Vehicle from '#fixtures/types/vehicle' +import type { PropertyDescriptor } from '#src/interfaces' +import type Class from '../class' +import type TestSubject from '../decorator-method' +import type Fn from '../fn' +import type OwnPropertyKey from '../property-key-own' + +describe('unit-d:types/MethodDecorator', () => { + type T = Fn<[vin: Vehicle['vin']], Vehicle> + type U = Class + + it('should be callable with [U, OwnPropertyKey, PropertyDescriptor]', () => { + // Arrange + type Expect = [U, OwnPropertyKey, PropertyDescriptor] + + // Expect + expectTypeOf>().parameters.toEqualTypeOf() + }) + + it('should return PropertyDescriptor | void', () => { + // Arrange + type Expect = PropertyDescriptor | void + + // Expect + expectTypeOf>().returns.toEqualTypeOf() + }) +}) diff --git a/src/types/decorator-class.ts b/src/types/decorator-class.ts new file mode 100644 index 00000000..cb4958fc --- /dev/null +++ b/src/types/decorator-class.ts @@ -0,0 +1,23 @@ +/** + * @file Type Definitions - ClassDecorator + * @module tutils/types/ClassDecorator + */ + +import type Constructor from './constructor' +import type AbstractConstructor from './constructor-abstract' + +/** + * A class decorator. + * + * @see https://www.typescriptlang.org/docs/handbook/decorators.html#class-decorators + * + * @template T - Class type + * + * @param {T} target - Class declaration + * @return {T | void} Class declaration or `undefined` + */ +type ClassDecorator = Constructor> = ( + target: T +) => T | void + +export type { ClassDecorator as default } diff --git a/src/types/decorator-method.ts b/src/types/decorator-method.ts new file mode 100644 index 00000000..9d018082 --- /dev/null +++ b/src/types/decorator-method.ts @@ -0,0 +1,34 @@ +/** + * @file Type Definitions - MethodDecorator + * @module tutils/types/MethodDecorator + */ + +import type { PropertyDescriptor } from '#src/interfaces' +import type DecoratorTarget from './decorator-target' +import type Fn from './fn' +import type OwnPropertyKey from './property-key-own' + +/** + * A method decorator. + * + * @see {@linkcode DecoratorTarget} + * @see https://www.typescriptlang.org/docs/handbook/decorators.html#method-decorators + * + * @template T - Property descriptor value type + * @template U - Class constructor or instance type + * + * @param {U} target - Class declaration or prototype + * @param {OwnPropertyKey} key - Method name + * @param {PropertyDescriptor} descriptor - Property descriptor for `key` + * @return {PropertyDescriptor | void} Property descriptor or `undefined` + */ +type MethodDecorator< + T extends Fn = Fn, + U extends DecoratorTarget = DecoratorTarget +> = ( + target: U, + key: OwnPropertyKey, + descriptor: PropertyDescriptor +) => PropertyDescriptor | void + +export type { MethodDecorator as default } diff --git a/src/types/index.ts b/src/types/index.ts index 1062934d..09a822ff 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -17,6 +17,8 @@ export type { default as Constructor } from './constructor' export type { default as AbstractConstructor } from './constructor-abstract' export type { default as ContinuousValue } from './continuous-value' export type { default as Crush } from './crush' +export type { default as ClassDecorator } from './decorator-class' +export type { default as MethodDecorator } from './decorator-method' export type { default as DecoratorTarget } from './decorator-target' export type { default as Defaults } from './defaults' export type { default as Digit } from './digit'