0.0.4 • Published 5 years ago

@sullux/fp-light-type v0.0.4

Weekly downloads
-
License
MIT
Repository
github
Last release
5 years ago

home

fp-light-type

npm i @sullux/fp-light-type source test

The type function supplements the scattered and inconsistent type-related functionality in Javascript. This includes supplying proper factory functions for undefined and null, the only values in Javascript that are missing a native factory. This also includes a utility to define new types in a consistent way.

allProperties

allProperties(object: any): { [name: string | Symbol]: Descriptor }

Enumerates the properties of the given object and every prototype in the prototype chain of the given object, returning a map of property names/symbols to descriptors. See the Node.js reference for Object.defineProperty for details about the descriptors.

Note that the result includes non-enumerable properties. The following example shows the REPL output of the function.

allProperties(Error('reasons'))
/*
{ stack:
   { value: 'Error: reasons\n    at repl:1:15\n    at ContextifyScript.Script.runInThisContext (vm.js:50:33)\n    at REPLServer.defaultEval (repl.js:240:29)\n    at bound (domain.js:301:14)\n    at REPLServer.runBound [as eval] (domain.js:314:12)\n    at REPLServer.onLine (repl.js:468:10)\n    at emitOne (events.js:121:20)\n    at REPLServer.emit (events.js:211:7)\n    at REPLServer.Interface._onLine (readline.js:280:10)\n    at REPLServer.Interface._line (readline.js:629:8)',
     writable: true,
     enumerable: false,
     configurable: true },
  message:
   { value: '',
     writable: true,
     enumerable: false,
     configurable: true },
  constructor:
   { value: [Function: Object],
     writable: true,
     enumerable: false,
     configurable: true },
  name:
   { value: 'Error',
     writable: true,
     enumerable: false,
     configurable: true },
  toString:
   { value: [Function: toString],
     writable: true,
     enumerable: false,
     configurable: true },
  __defineGetter__:
   { value: [Function: __defineGetter__],
     writable: true,
     enumerable: false,
     configurable: true },
  __defineSetter__:
   { value: [Function: __defineSetter__],
     writable: true,
     enumerable: false,
     configurable: true },
  hasOwnProperty:
   { value: [Function: hasOwnProperty],
     writable: true,
     enumerable: false,
     configurable: true },
  __lookupGetter__:
   { value: [Function: __lookupGetter__],
     writable: true,
     enumerable: false,
     configurable: true },
  __lookupSetter__:
   { value: [Function: __lookupSetter__],
     writable: true,
     enumerable: false,
     configurable: true },
  isPrototypeOf:
   { value: [Function: isPrototypeOf],
     writable: true,
     enumerable: false,
     configurable: true },
  propertyIsEnumerable:
   { value: [Function: propertyIsEnumerable],
     writable: true,
     enumerable: false,
     configurable: true },
  valueOf:
   { value: [Function: valueOf],
     writable: true,
     enumerable: false,
     configurable: true },
  __proto__:
   { get: [Function: get __proto__],
     set: [Function: set __proto__],
     enumerable: false,
     configurable: true },
  toLocaleString:
   { value: [Function: toLocaleString],
     writable: true,
     enumerable: false,
     configurable: true } }
*/

bindAll

bindAll<T>(object: T): T

Iterates all properties on the given object and the object's prototype chain and binds all functions to the given object. This solves a wide range of bugs that occur when an instance function is called out of context. The following test demonstrates the solution.

const { strictEqual, throws } = require('assert')

const { bindAll } = require('@sullux/fp-light-type')

class Foo {
  constructor() {
    this.x = 42
  }
  xString() {
    return this.x.toString()
  }
}

describe('bindAll', () => {
  it('should throw without binding', () => {
    const unbound = new Foo()
    throws(unbound.xString)
  })
  it('should work properly with binding', () => {
    const bound = bindAll(new Foo())
    strictEqual(bound.xString(), '42')
  })
})

define

define(name: string, options: ?{ extend: ?Function, construct: ?(...args: mixed[]) => Object, enumerable: ?{ [name: String | Symbol]: mixed }, hidden: ?{ [name: String | Symbol]: mixed }, properties: ?{ [name: String | Symbol]: Descriptor }, describe, }): Function

At the most basic level, the define utiliy defines a function that will behave the same whether called as a factory or as a constructor.

const Foo = define('Foo')
const foo1 = Foo()
const foo2 = new Foo()

is equivalent to

function Foo () {
  return new.target
    ? this
    : Object.setPrototypeOf({}, Foo.prototype)
const foo1 = bindAll(Foo())
const foo2 = bindAll(new Foo())
}

While this removes much of the underlying complexity of constructors and factories, defining a type would not be useful without the various options.

extend

Sets the parent constructor of the given type. The following example demonstrates defining a custom error.

const FooError = define('FooError', { extend: Error })
const error = FooError()
error instanceof FooError // true
error instanceof Error // true

construct

Allows a custom-constructed base object for a new instance of the type. The construct function's this is the new instance and the return value of the construct function will be also be composed onto the new instance.

const FooError = define('FooError', {
  extend: Error,
  construct(message) {
    this.id = 'Foo123'
    return Error(message)
  },
})
const error = new FooError('reasons')
error.id // Foo123
error.message // reasons
error.stack
/*
Error: reasons
    at FooError.construct (repl:1:76)
    ...etc.
*/

enumerable

Defines enumerable properties to be added to the defined prototype. Defining a property as enumerable is similar to making it public in the sense that it is discoverable by looping structures and functions that iterate enumerable properties such as Object.keys.

Note that the following is the same example as for construct except that instead of modifying each instance during construction, the id property is now an enumerable property of the prototype.

const FooError = define('FooError', {
  extend: Error,
  construct: Error,
  enumerable: { id: 'Foo123' },
})
const error = new FooError('reasons')
error.id // Foo123
error.message // reasons
error.stack
/*
Error: reasons
    at FooError.construct (repl:1:76)
    ...etc.
*/

hidden

Defines hidden (non-enumerable) properties on the defined prototype. Note that a hidden property is not private in the traditional sense because it can still be accessed externally. It is only hidden from discovery by looping structures and functions that iterate enumerable properties.

const Foo = define('Foo', { hidden: { secret: 42 } })
const foo = new Foo()
Object.keys(foo).includes('secret') // false
foo.secret // 42

properties

Defines property descriptors for the defined prototype. This allows the definition of properties with getters and setters, non-configurable properties, etc.

const Foo = define('Foo', {
  properties: {
    answer: { get() { return 42 } },
  },
})
const foo = new Foo()
Object.keys(foo).includes('answer') // false
foo.answer = 1
foo.answer // 42

describe

The describe function is a special helper that is called by the Node.js utility function util.inspect() to generate a string representation of an object. This is called by the REPL to provide console output.

const Foo = define('Foo', { describe: () => 'instance of Foo' })
const Bar = define('Bar')
console.log(new Foo())
// instance of Foo
console.log(new Bar())
// [Object Bar]

factoryOf

factoryOf(value: any): Function

Given a value, returns the factory of the value.

Example:

const { strictEqual } = require('assert')
const { factoryOf } = require('@sullux/fp-light-type')

strictEqual(factoryOf(true), Boolean)

Null

Null(): null

Provided as the missing factory/constructor for null.

Example:

const { strictEqual } = require('assert')
const { Null, factoryOf } = require('@sullux/fp-light-type')

strictEqual(Null(), null)
strictEqual(factoryOf(null), Null)

type

type(value: any): { jstype: string, name: string, factory: Function, inheritance: Array<string> }

Returns a map of information about the type of the given value.

  • jstype: the native type as reported by typeof value.
  • name: the name of the factory function for this type.
  • factory: the factory function for this type.
  • inheritance: an array of all factory functions within the prototype chain from the factory of the given value through the final factory Object.

Example:

const { type } = require('@sullux/fp-light-type')

console.log(type(true))
/*
{ jstype: 'boolean',
  name: 'Boolean',
  factory: [Function: Boolean],
  inheritance: [ [Function: Boolean], [Function: Object] ] }
*/

typeEquals

typeEquals(first: any, second: any): boolean

Given two values, returns true if the values share the same factory function.

Example:

const { ok } = require('assert')
const { typeEquals } = require('@sullux/fp-light-type')

ok(typeEquals(false, true))
ok(typeEquals(null, null))
ok(!typeEquals(null, undefined))

Undefined

Undefined(): undefined

Provided as the missing factory/constructor for undefined.

Example:

const { strictEqual } = require('assert')
const { Undefined, factoryOf } = require('@sullux/fp-light-type')

strictEqual(Undefined(), undefined)
strictEqual(factoryOf(undefined), Undefined)
0.0.4

5 years ago

0.0.3

5 years ago

0.0.2

5 years ago

0.0.1

5 years ago