@zacharygriffee/interface v1.1.10
z-interface
An Interface implementation for vanilla Javascript
An interface aim is to prohibit access to all resources by default, allowing access only through well-defined entry points, Wikipedia
Installation
npm install @zacharygriffee/interface --save
Import
import {Interface, canInterface, isInterface, SYMBOLS} from "@zacharygriffee/interface";
Usage examples
Create interface
// interfaces.js
// Use the 'design factory'
export const IName = Interface(
({Accessor}) => ({
name: Accessor
})
);
// Or import the symbols and use them in an object.
const {Get, Function} = SYMBOLS;
export const IAge = Interface({age: Get});
export const IWalk = Interface({walk: Function});
export const INameAndAge = Interface({
IName, IAge
});
export const IFly = Interface({
Fly: Get
});
Use Interface
Interface any object
// Create an object to interface
function createPerson(name, age) {
return {
get age() {
return age;
},
set name(value) {
name = value;
},
get name() {
return name;
},
walk() {
return this.name + " walking";
},
beamedUp() {
return this.name + " beamed up";
}
}
}
const piccard = createPerson('Piccard', 42);
Use the interfaced (object | class instance)
import {
IName,
IAge,
IWalk,
INameAndAge,
IFly
} from "./interfaces.js";
isInterface(IWalk); // true
canInterface(IWalk, piccard); // true
Interface.canInterface(IAge, piccard); // true
canInterface(IFly, piccard); // false, Piccard needs the enterprise to fly.
const walker = IWalk(piccard);
const age = IAge(piccard);
const nameAndAge = INameAndAge(piccard);
// CAN
walker.walk(); // "Piccard walking'
age.age; // 42
nameAndAge = "Captain Piccard"; // sets the name of the interfaced instance
piccard.name; // "Captain Piccard"
nameAndAge.age; // 42
// CANNOT
const walkerAge = walker.age; // undefined, IWalk doesn't have access to age
walker.beamedUp(); // throws 'function doesn't exist'
age.age = 12; // IAge only has a getter, this will throw TypeError
API
Interface(designOrDesignFactory)
There are two ways to create an interface.
One | Design
import {SYMBOLS, Interface} from "@zacharygriffee/interface";
const {
Get, Set, Accessor
} = SYMBOLS;
Interface({
name: Accessor, // The interface will have both get and set access.
age: Get // The interface will only have Get access to 'age'
});
Two | Design Factory
Pass a function as first argument of Interface and use destructuring to access the SYMBOLS
import {Interface} from "@zacharygriffee/interface";
Interface(({Get, Accessor}) =>
({
name: Accessor,
age: Get
})
);
// OR verbosely
Interface((SYMBOLS) => {
return {
name: SYMBOLS.Accessor,
age: SYMBOLS.Get
}
}
);
Interface a target (Object | Class Instance)
const IName = Interface({name: SYMBOLS.Get});
let _name = "Captain Piccard";
const target = {
get name() {
return _name;
},
set name(val) {
_name = val;
}
};
const personName = IName(target);
personName.name; // Captain Piccard
personName.name = "Q"; // throws TypeError, interface doesn't implement setter.
bool = interface.canInterface(target)
Check if an interface can interface a target.
IWalk.canInterface(piccard); // true
SYMBOLS
Let
The property can be anything of target. The interface can do anything with this property.
Get
The target must have a getter. The interface will only have read access to this property.
Set
The target must have a setter. The interface will only have write access to this property.
Accessor
The target must have both a getter and setter. The interface will have both read and write access.
Fluent
Same as accessor however it changes the property behavior to allow for chaining; useful with observables.
const piccard = INameAndAge(person); // Assume name and age both are 'Fluent'
piccard.name("Captain Piccard").age(43); // The set method returns the interface to chain.
piccard.name // Captain Piccard
piccard.age // 43
// Example with rxjs
rx.of(piccard).pipe(
rx.map(piccard => piccard.name("Captain Piccard")),
rx.map(piccard => piccard.age(44))
);
Object
The property of target must be an object.
Array
The property of target must be an array.
Function
The property of target must be a function.
Async
| Promise
The property of target must be thenable | async. value = Promise.resolve(42)
AsyncFunction
The property of target must be an async function. e.g. async imAsync() { /* do async things */ }
Observable
The property of target must be an observable. To satisfy, the target must have subscribe
and lift
function.
Observer
The property of target must be an observer. Either a standard function or an object containing
at least one of these functions next
, error
, complete
Subject
The property of target must satisfy both observable and observer validations above.
Utilities
bool = Interface.isInterface(interface)
Check whether interface
is an Interface made by z-interface.
bool = Interface.canInterface(interface, target)
Check whether 'target' can be interfaced by 'interface'.
Test it
npm test
Distributed under the MIT license. See LICENSE
for more information.