UNPKG

stampit

Version:

Create objects from reusable, composable behaviors.

361 lines (320 loc) 16.4 kB
// Type definitions for stampit 5 // Project: https://github.com/stampit-org/stampit, https://stampit.js.org // Definitions by: Vasyl Boroviak <https://github.com/koresar> // Harris Lummis <https://github.com/lummish> // PopGoesTheWza <https://github.com/popgoesthewza> // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped // TypeScript Version: 3.5 // Utility types /** * @internal Base type for all `methods`-like metadata. * @template This The type to use for `this` within methods. */ interface MethodMap<This> { [s: string]: ((this: This, ...args: any[]) => any) | {}; } /** @internal A plain old JavaScript object created by a `Stamp`. */ type Pojo = object; // { [s: string]: any; } /** @internal Base type for all `properties`-like metadata. */ // TODO: discriminate Array type PropertyMap = object; // { [s: string]: any; } /** @internal Signature common to every `Stamp`s. */ interface StampSignature { (options?: PropertyMap, ...args: unknown[]): any; compose: ComposeMethod & stampit.Descriptor<any, any>; } /** * @internal Extracts the `Stamp` type. * @template Original The type to extract the `Stamp` type from. */ type StampType<Original> = Original extends /* disallowed types */ [] | bigint ? never : stampit.IsADescriptor<Original> extends true ? Original extends stampit.ExtendedDescriptor<infer Obj, infer Stamp> ? Stamp : never : unknown extends Original /* is any or unknown */ ? stampit.Stamp<Original> : Original extends StampSignature ? Original : Original extends stampit.ExtendedDescriptor<infer Obj, any> ? stampit.Stamp<Obj> : Original extends Pojo ? stampit.Stamp<Original> /*assume it is the object from a stamp object*/ : never; /** * @internal The type of the object produced by the `Stamp`. * @template Original The type (either a `Stamp` or a `ExtendedDescriptor`) to get the object type from. */ type StampObjectType<Original> = Original /* disallowed types */ extends bigint | boolean | number | string | symbol ? never : stampit.IsADescriptor<Original> extends true ? Original extends stampit.ExtendedDescriptor<infer Obj, any> ? Obj : never : unknown extends Original /* is any or unknown */ ? Original : Original extends StampSignature ? Original extends stampit.Stamp<infer Obj> /* extended stamps may require infering twice */ ? Obj extends stampit.Stamp<infer Obj> ? Obj : Obj : any : Original extends stampit.ExtendedDescriptor<infer Obj, any> ? Obj : Original extends Pojo ? Original : never; /** * A factory function to create plain object instances. * @template Obj The object type that the `Stamp` will create. */ interface FactoryFunction<Obj> { (options?: PropertyMap, ...args: any[]): StampObjectType<Obj>; } /** * @internal Chainables `Stamp` additional methods * @template Obj The object type that the `Stamp` will create. */ type StampChainables<Obj> = Chainables<StampObjectType<Obj>, StampType<Obj>>; /** * @internal Chainables `Stamp` additional methods * @template Obj The object type that the `Stamp` will create. * @template S The type of the `Stamp` (when extending a `Stamp`.) */ interface Chainables<Obj, S extends StampSignature> { /** * Add methods to the methods prototype. Creates and returns new Stamp. **Chainable**. * @template This The type to use for `this` within methods. * @param methods Object(s) containing map of method names and bodies for delegation. */ // tslint:disable-next-line: no-unnecessary-generics methods<This = Obj>(...methods: Array<MethodMap<This>>): S; /** * Take a variable number of objects and shallow assign them to any future created instance of the Stamp. Creates and returns new Stamp. **Chainable**. * @param objects Object(s) to shallow assign for each new object. */ properties(...objects: PropertyMap[]): S; /** * Take a variable number of objects and shallow assign them to any future created instance of the Stamp. Creates and returns new Stamp. **Chainable**. * @param objects Object(s) to shallow assign for each new object. */ props(...objects: PropertyMap[]): S; /** * Take a variable number of objects and deeply merge them to any future created instance of the Stamp. Creates and returns a new Stamp. **Chainable**. * @param deepObjects The object(s) to deeply merge for each new object. */ deepProperties(...deepObjects: PropertyMap[]): S; /** * Take a variable number of objects and deeply merge them to any future created instance of the Stamp. Creates and returns a new Stamp. **Chainable**. * @param deepObjects The object(s) to deeply merge for each new object. */ deepProps(...deepObjects: PropertyMap[]): S; /** * Take in a variable number of functions and add them to the initializers prototype as initializers. **Chainable**. * @param functions Initializer functions used to create private data and privileged methods. */ initializers(...functions: Array<stampit.Initializer<Obj, S>>): S; initializers(functions: Array<stampit.Initializer<Obj, S>>): S; /** * Take in a variable number of functions and add them to the initializers prototype as initializers. **Chainable**. * @param functions Initializer functions used to create private data and privileged methods. */ init(...functions: Array<stampit.Initializer<Obj, S>>): S; init(functions: Array<stampit.Initializer<Obj, S>>): S; /** * Take n objects and add them to a new stamp and any future stamp it composes with. Creates and returns new Stamp. **Chainable**. * @param statics Object(s) containing map of property names and values to mixin into each new stamp. */ staticProperties(...statics: PropertyMap[]): S; /** * Take n objects and add them to a new stamp and any future stamp it composes with. Creates and returns new Stamp. **Chainable**. * @param statics Object(s) containing map of property names and values to mixin into each new stamp. */ statics(...statics: PropertyMap[]): S; /** * Deeply merge a variable number of objects and add them to a new stamp and any future stamp it composes. Creates and returns a new Stamp. **Chainable**. * @param deepStatics The object(s) containing static properties to be merged. */ staticDeepProperties(...deepStatics: PropertyMap[]): S; /** * Deeply merge a variable number of objects and add them to a new stamp and any future stamp it composes. Creates and returns a new Stamp. **Chainable**. * @param deepStatics The object(s) containing static properties to be merged. */ deepStatics(...deepStatics: PropertyMap[]): S; /** * Take in a variable number of functions and add them to the composers prototype as composers. **Chainable**. * @param functions Composer functions that will run in sequence while creating a new stamp from a list of composables. The resulting stamp and the composables get passed to composers. */ composers(...functions: Array<stampit.Composer<S>>): S; composers(functions: Array<stampit.Composer<S>>): S; /** * Shallowly assign properties of Stamp arbitrary metadata and add them to a new stamp and any future Stamp it composes. Creates and returns a new Stamp. **Chainable**. * @param confs The object(s) containing metadata properties. */ configuration(...confs: PropertyMap[]): S; /** * Shallowly assign properties of Stamp arbitrary metadata and add them to a new stamp and any future Stamp it composes. Creates and returns a new Stamp. **Chainable**. * @param confs The object(s) containing metadata properties. */ conf(...confs: PropertyMap[]): S; /** * Deeply merge properties of Stamp arbitrary metadata and add them to a new Stamp and any future Stamp it composes. Creates and returns a new Stamp. **Chainable**. * @param deepConfs The object(s) containing metadata properties. */ deepConfiguration(...deepConfs: PropertyMap[]): S; /** * Deeply merge properties of Stamp arbitrary metadata and add them to a new Stamp and any future Stamp it composes. Creates and returns a new Stamp. **Chainable**. * @param deepConfs The object(s) containing metadata properties. */ deepConf(...deepConfs: PropertyMap[]): S; /** * Apply ES5 property descriptors to object instances created by the new Stamp returned by the function and any future Stamp it composes. Creates and returns a new stamp. **Chainable**. * @param descriptors */ propertyDescriptors(...descriptors: PropertyDescriptorMap[]): S; /** * Apply ES5 property descriptors to a Stamp and any future Stamp it composes. Creates and returns a new stamp. **Chainable**. * @param descriptors */ staticPropertyDescriptors(...descriptors: PropertyDescriptorMap[]): S; } /** * A function which creates a new `Stamp`s from a list of `Composable`s. * @template Obj The type of the object instance being produced by the `Stamp` or the type of the `Stamp` being created (when extending a `Stamp`.) */ type ComposeMethod = typeof stampit; /** * A function which creates a new `Stamp`s from a list of `Composable`s. * @template Obj The type of the object instance being created by the `Stamp` or the type of the `Stamp` being created (when extending a `Stamp`.) */ // tslint:disable-next-line: no-unnecessary-generics declare function stampit<Obj = any>(...composables: stampit.Composable[]): StampType<Obj>; declare namespace stampit { /** A composable object (either a `Stamp` or a `ExtendedDescriptor`.) */ type Composable = StampSignature | ExtendedDescriptor<any, any>; /** * A `Stamp`'s metadata. * @template Obj The type of the object instance being produced by the `Stamp`. * @template S The type of the `Stamp` (when extending a `Stamp`.) */ interface Descriptor<Obj, S extends StampSignature = Stamp<Obj>> { /** A set of methods that will be added to the object's delegate prototype. */ methods?: MethodMap<Obj>; /** A set of properties that will be added to new object instances by assignment. */ properties?: PropertyMap; /** A set of properties that will be added to new object instances by deep property merge. */ deepProperties?: PropertyMap; /** A set of object property descriptors (`PropertyDescriptor`) used for fine-grained control over object property behaviors. */ propertyDescriptors?: PropertyDescriptorMap; /** A set of static properties that will be copied by assignment to the `Stamp`. */ staticProperties?: PropertyMap; /** A set of static properties that will be added to the `Stamp` by deep property merge. */ staticDeepProperties?: PropertyMap; /** A set of object property descriptors (`PropertyDescriptor`) to apply to the `Stamp`. */ staticPropertyDescriptors?: PropertyDescriptorMap; /** An array of functions that will run in sequence while creating an object instance from a `Stamp`. `Stamp` details and arguments get passed to initializers. */ initializers?: Initializer<Obj, S> | Array<Initializer<Obj, S>>; /** An array of functions that will run in sequence while creating a new `Stamp` from a list of `Composable`s. The resulting `Stamp` and the `Composable`s get passed to composers. */ composers?: Array<Composer<S>>; /** A set of options made available to the `Stamp` and its initializers during object instance creation. These will be copied by assignment. */ configuration?: PropertyMap; /** A set of options made available to the `Stamp` and its initializers during object instance creation. These will be deep merged. */ deepConfiguration?: PropertyMap; } /** * A `stampit`'s metadata. * @template Obj The type of the object instance being produced by the `Stamp`. * @template S The type of the `Stamp` (when extending a `Stamp`.) */ interface ExtendedDescriptor<Obj, S extends StampSignature = Stamp<Obj>> extends Descriptor<Obj, S> { /** A set of properties that will be added to new object instances by assignment. */ props?: PropertyMap; /** A set of properties that will be added to new object instances by deep property merge. */ deepProps?: PropertyMap; /** A set of static properties that will be copied by assignment to the `Stamp`. */ statics?: PropertyMap; /** A set of static properties that will be added to the `Stamp` by deep property merge. */ deepStatics?: PropertyMap; /** An array of functions that will run in sequence while creating an object instance from a `Stamp`. `Stamp` details and arguments get passed to initializers. */ init?: Initializer<Obj, S> | Array<Initializer<Obj, S>>; /** A set of options made available to the `Stamp` and its initializers during object instance creation. These will be copied by assignment. */ conf?: PropertyMap; /** A set of options made available to the `Stamp` and its initializers during object instance creation. These will be deep merged. */ deepConf?: PropertyMap; /** The `name` property of the `Stamp`. Will be assigned to `MyStamp.name`. */ name?: string; } /** * @internal Checks that a type is a ExtendedDescriptor (except `any` and `unknown`). * @template Type A type to check if a ExtendedDescriptor. */ // TODO: Improve test by checking the type of common keys type IsADescriptor<Type> = unknown extends Type ? keyof Type extends never ? false : keyof Type extends infer K ? K extends keyof ExtendedDescriptor<unknown> ? true : false : false : false; /** * A function used as `.initializers` argument. * @template Obj The type of the object instance being produced by the `Stamp`. * @template S The type of the `Stamp` producing the instance. */ interface Initializer<Obj, S extends StampSignature> { (this: Obj, options: /*_propertyMap*/ any, context: InitializerContext<Obj, S>): void | Obj; } /** * The `Initializer` function context. * @template Obj The type of the object instance being produced by the `Stamp`. * @template S The type of the `Stamp` producing the instance. */ interface InitializerContext<Obj, S extends StampSignature> { /** The object instance being produced by the `Stamp`. If the initializer returns a value other than `undefined`, it replaces the instance. */ instance: Obj; /** A reference to the `Stamp` producing the instance. */ stamp: S; /** An array of the arguments passed into the `Stamp`, including the options argument. */ // ! above description from the specification is obscure args: any[]; } /** * A function used as `.composers` argument. * @template S The type of the `Stamp` produced by the `.compose()` method. */ interface Composer<S extends StampSignature> { (parameters: ComposerParameters<S>): void | S; } /** * The parameters received by the current `.composers` function. * @template S The type of the `Stamp` produced by the `.compose()` method. */ interface ComposerParameters<S extends StampSignature> { /** The result of the `Composable`s composition. */ stamp: S; /** The list of composables the `Stamp` was just composed of. */ composables: Composable[]; } /** * A factory function to create plain object instances. * * It also has a `.compose()` method which is a copy of the `ComposeMethod` function and a `.compose` accessor to its `Descriptor`. * @template Obj The object type that the `Stamp` will create. */ interface Stamp<Obj> extends FactoryFunction<Obj>, StampChainables<Obj>, StampSignature { /** Just like calling stamp(), stamp.create() invokes the stamp and returns a new instance. */ create: FactoryFunction<Obj>; /** * A function which creates a new `Stamp`s from a list of `Composable`s. * @template Obj The type of the object instance being produced by the `Stamp`. or the type of the `Stamp` being created. */ compose: ComposeMethod & Descriptor<StampObjectType<Obj>>; } /** A function which creates a new `Stamp`s from a list of `Composable`s. */ const compose: ComposeMethod; } // tslint:disable-next-line: npm-naming export default stampit;