Common interfaces and types for typescript, such Predicate
or Maybe
. This is of no use if you do not use typescript.
I made this because I often ended up needing and writing the same types for my projects.
Types are used only when transpiling, they do not end up in the transpiled code. Ie, your transpiled code does not get bigger by using this library.
Documentation and list of all the interfaces and types.
The drill:
npm install --save andross
Now you can import the types
All available and types are exposed from the main file.
// import this lib
import { Predicate, Maybe, Comparator } from "andross";
// Use the interfaces and type.
class Users<T> {
private users: Users[];
constructor() {
this.users = [];
}
getUserById(id: number): Maybe<User> {
return this.users.find(user => user.id === id);
}npx tslint -c tslint.json main.ts
getUsers(filter: Predicate<User>): User[] {
return this.users.filter(filter);
}
sort(comparator: Comparator<T>) {
this.users.sort(comparator);
}
}
As of version 0.3.4, this package also includes some predefined enumerations. Since these are not purely type definitions and contribute to the size of a bundle, they are placed in a separate file and not included in the main file:
import { CardinalDirection4 } from "andross/enum";
const north = CardinalDirection4.North;
See the documentation for a list of all interfaces and types with a short description.
PickPartial
, PickMatching
, PickAssignable
, PartialKeys
, AssignableKeys
, RequiredFor
.Voidable
.ReversibleFunction
, ReversibleBiFunction
, ReversibleTriFunction
.Equatable
and added defaults for type parameters of BiConsumer
/TriConsumer
and BiSupplier
/TriSupplier
.K
to StringObject
, allowing you to restrict the available keys. Also removed the *.ts
source files from the NPM package. The source file made webpack with ts-loader
work incorrectly.RectSize
, Rectangle
, MinMaxRectangle
, CardinalDirection4/8/16/32
, ReadonlyFor
, ReadonlyExcept
, MatchingKeys
.PartialExcept
(makes every property but the given optional) and PartialFor
(makes every given property optional).RemoveFrom
. Tuple types generics now default to the previous type, ie. Pair<string>
is equivalent to Pair<string, string>
.Builder
type.Vector1
, Vector2
, Vector3
, Vector4
, Vector5
), StringObject
and NumberObject
, as well as Omit
and Overwrite
May not work on Windows.
git clone https://github.com/blutorange/js-andross
cd js-andross
npm install
npm run build
The great (inter-)face of Andross.
Same as Consumer, but accepts two items to be consumed.
Same as Predicate, but accepts two parameters.
Same as a Supplier, but returns two items.
A binary operator takes two items of the same type and coputes a result of the same type.
const multiply: BinaryOperator<number> = (x, y) => x * y;
[1,2,3,4,5].reduce(multiply, 1); // => 120
List of the sixteen cardinal directions.
List of the thirty-two cardinal directions.
List of the four cardinal directions.
List of the eight cardinal directions.
A comparator that takes two objects and compares them. Returns a negative or
positive number to indicate the first object is less or greater than the
second object; or 0
iff both objects are equal.
const myComparator = (lhs, rhs) => rhs - lhs;
[3, 1, 2].sort(myComparator);
// => [3, 2, 1]
Represents the constructor a class, ie. the `constructor functions that returns a new instance of the class.
// Creates a new instance and injects all dependencies.
function create<T>(container: Constructor<T>, ...args: []) {
const instance = new container(...args);
// inject some properties
return instance;
}
A consumer is a sink that takes an item and performs some action with it, but does not return anything.
function getViaAjax(endpoint: string, onDone: Consumer<object>) {
fetch(endpoint)
.then(response => JSON.parse(readBody(response)));
.catch(e => console.error("Could not fetch data", e));
}
A 10-tuple with ten elements.
Consider an object with some known property keys. A partial is another
object that may contain none or only some of these keys, but no keys not
present in the original object. This is what the built-in type Partial
provides. A deep partial generalize this notion to nested properties.
// Represents a physical address of a building etc.
class Address() {
constructor(public country: string, public city: string, public street: string) {}
}
// Represents a user with an ID, a name, and a date of birth.
class User {
constructor(public id: number, public name: string, residence: Address) {}
}
// A function that searches a user matching some criteria. By using a
// DeepPartial, `typescript` allows only keys and properties that are
// part of a User. It also checks whether the type of the property is
// correct.
function findUserBy(criteria: DeepPartial<User>) {
// to be implemented, read from a database or in-memory
return user;
}
// Now we can query users by their propeties.
findUserBy({
id: 9,
});
findUserBy({
name: "Masahiko",
residence: {
country: "Japan",
}
});
findUserBy({
residence: {
city: "London",
street: "Baker Street",
}
});
Takes a type and filter them, leaving only types that have a given property of a given type.
interface Square {
kind: "square",
geometry: {
side: number;
}
}
interface Circle {
kind: "circle",
geometry: {
radius: number;
}
}
interface Rectangle {
kind: "rectangle",
geometry: {
horizontalSide: number;
verticalSide: number;
}
}
interface Ellipsis {
kind: "ellipsis",
geometry: {
horizontalHalfAxis: number;
verticalHalfAxis: number;
}
}
// Union of all shapes
type Shape = Square | Circle | Rectangle | Ellipsis;
// Select a particular shape when given its kind
type ellipsis = DiscriminateUnion<Shape, "kind", "ellipsis">;
An equator that takes to items and checks whether they are equal to each other.
const sameLength : Equator<string> = (lhs, rhs) => lhs.length === rhs.length;
["a", "aa", "aaa"].find(sameLength.bind(null, "me"))
A JSON compound value (JSONArray or JSONObject).
A primitive JSON value.
A JSON value (primitive or compound).
Extracts a key from an object used for comparing the object to other objects.
class Customer {
constructor(public id: number, public name: string) {}
static keyId(customer: Customer): number {
return customer.id;
}
static keyName(customer: Customer): string {
return customer.name;
}
}
const collection = new IndexedCollection<Customer>();
const byId = collection.createOrderedIndex<number>({key: Customer.byId});
const byName = collection.createOrderedIndex<string>({key: Customer.byName});
// add some customers
// ...
byId.getAt(9);
byName.getAt("Cleopatra");
A key-value pair as an array tuple. Used eg. by Map#entries.
const Map<number, User> users = new Map();
const entries: Iterable<KeyValuePair<number, User>> = users.entries();
Gives all property keys whose types match the given type.
interface User {
active: boolean;
age: number;
mail: string;
name: string;
username: string;
}
function foo(stringKey: MatchingKeys<User, string>) {
// Variable stringKey now has the type
// "mail" | "name" | "username"
const b1 = stringKey === "mail"; // works
const b2 = stringKey === "name"; // works
const b3 = stringKey === "username"; // works
// [ts] Operator '===' cannot be applied to types '"mail" | "name" | "username"' and '"active"'.
const b4 = stringKey === "active";
}
// Variable advanced now has the type
// "mail" | "name"
declare const advanced = MatchingKeys<User, string, "age" | "mail" | "name">;
Represents an optional value. Absence of the value is indicated
by undefined
. JavaScript provides tow different types for the notion of
absende, namely null
and undefined
, with minor semantic differences.
However, for the sake of clarity and simplicity, I am in favor of using only
one type whenever a value is absent. undefined
is suited better as it is
the default value when declaring a variable and used for optional function
parameters.
Consider enabling strictNullChecks
with typescript to check for possibly
undefined values.
function getLength(word: Maybe<string>) {
return word !== undefined ? word.length : 0;
}
A 9-tuple with nine elements.
An 8-tuple with eight elements.
From T omit a set of properties K.
// Takes a vector3 that does not need to have a z-coordinate.
function projectToXY(vector: Omit<Vector3, "z"): Vector2 {
return {x: vector.x, y: vector.y};
}
Takes a type and create a new type with some properties overwritten with a different type.
// Somewhere options are defined, and only an ID is required.
interface Options {
id: number,
foo?: string,
bar?: string,
}
// ...
// Now we want to create a function that takes an `Options` object,
// but with the foo property mandatory.
function createOptions(opts: Overwrite<Options, {foo: string}) {
console.log(opts.foo) // Now opts.foo cannot be undefined.
}
A 2-tuple with two elements.
Makes every property optional, except for the given ones.
interface Entity {
id: number;
uuid: string;
}
interface User extends Entity {
username: string;
active: boolean;
age: number;
mail: string;
name: string;
// ...
}
// Same as PartialExcept<User, "id" | "uuid">
function createEntity<T extends Entity>(data: PartialExcept<User, keyof Entity>) {
// ...
}
createEntity({id: 1, uuid: "foo"}); // works
createEntity({id: 1, age: 9}); // error: property uuid is missing
Makes every given property optional.
interface User {
username: string;
active: boolean;
age: number;
mail: string;
name: string;
// ...
}
// Makes the properties age and mail optional.
declare const user: PartialFor<User, "age" | "mail">;
Shortcut for AssignableKeys<TRecord, undefined, K>
. Gives all property keys
that are optional, ie. to which undefined
can be assigned.
interface Data {
foo: number;
bar?: number;
baz: string|undefined;
}
// "bar"|"baz"
type PartialData = PartialKeys<Data>;
From TRecord, pick a set of properties to which the given type can be assigned.
interface Data {
foo: string | number;
bar?: number;
baz: string;
}
// {foo: string|number, baz: string}
type StringData = PickAssignable<Data, string>;
From TRecord, pick a set of properties that match the given type.
interface Data {
foo: string | number;
bar?: number;
baz: string;
}
// {baz: string}
type StringData = PickAssignable<Data, string>;
Pick the set of properties that are optional, eg. to which undefined
can be assigned.
abstract class Model<TAttributes> {
private attributes: TAttributes;
constructor(attributes: TAttributes) {
this.attributes = Object.assign({}, this.getDefaults(), attributes);
}
// Must return defaults for all optional attributes.
abstract getDefaults(): Required<PickPartial<TAttributes>>;
}
interface UserAttributes {
username: string;
age?: number;
email?: string;
}
class UserModel extends Model<UserAttributes> {
getDefaults() {
return {
email: "johndoe@example.com",
age: 18,
};
}
}
A predicate that takes an items and check for a condition.
const isOdd : Predicate<number> = x => x % 2 === 1;
[1,2,3,4,5,6,7,8,9].filter(isOdd) // => [1,3,5,7,9]
A 4-tuple with four elements.
A 5-tuple with five elements.
Makes every given property readonly, except for the given properties.
interface User {
username: string;
active: boolean;
age: number;
mail: string;
name: string;
// ...
}
// Makes all properties but age and mail readonly.
declare const user: ReadonlyExcept<User, "age" | "mail">;
Makes every given property readonly.
interface User {
username: string;
active: boolean;
age: number;
mail: string;
name: string;
// ...
}
// Makes the properties age and mail readonly.
declare const user: ReadonlyFor<User, "age" | "mail">;
A type without all properties of the other type.
interface Options {
id: number;
name: string;
mail: string;
}
interface InternalOptions {
id: number;
}
let idProvider = 0;
function createOptions<T>(additionalOptions: Partial<RemoveFrom<Options, InternalOptions>> = {}): Options {
return {
id: idProvider++,
mail: additionalOptions.mail || "foo@example.com"
name: additionalOptions.name || "foo",
};
}
// ...
const opts1 = createOptions({name: "blutorange"}); // WORKS
const opts2 = createOptions({id: 1}) // TYPE ERROR
A runnable is a function performs some operation when it is called, possibly with side effects, but does not return any value.
function runTest(test: Runnable) {
const t1 = Date.now();
try {
test();
console.log("Test successful");
}
catch(e) {
console.log("Test failed.");
}
finally {
const t2 = Date.now();
console.log(`Took ${(b-a)/1000} s`);
}
}
runTest( () => JSON.parse(inputData) );
A 7-tuple with seven elements.
A 6-tuple with six elements.
A 1-tuple with one element.
Similar to typescripts built-in type Record
,
but with the order of type parameters reverse
and the keys being optional.
An object with string keys and a given value type. Optionally, you can limit the available keys to a set of given keys.
const obj: StringObject<boolean> = {
foo: true,
bar: false,
foobar: false,
};
const obj2: StringObject<boolean, "foo" | "bar"> = {
foo: true,
bar: false,
// Object literal may only specify known properties, and 'foobar'
// does not exist in type 'StringObject<boolean, "foo" | "bar">'.
foobar: false
};
A supplier produces a value without an explicit input.
// A logging function for messages that may be costly to produce, eg. that
// may involve serialzing a deep object graph for debugging purposes. A
// supplier can be used to create the logging message only when the logging
// level is set to debug.
function debug(messageSupplier: Supplier<string>): void {
if (loggingLevel === "debug") {
console.debug(messageSupplier());
}
}
Same as Consumer, but accepts three items to be consumed.
Same as Predicate, but accepts three parameters.
Same as a Supplier, but returns three items.
A 3-tuple with three elements.
Same as TypedFunction, but takes two arguments.
A function that takes a single argument and returns a value.
const stringLength;
["foo", "bar", "foobar"].map(stringLength);
Same as TypedFunction, but takes three arguments.
An operator takes an item of a given type and computes a result of the same type.
const negate: UnaryOperator<number> = x => -x;
[1,2,3,4,5].map(negate);
Given a discriminated (tagged) union, creates a map between the tag (discriminant) and the corresponding type.
interface Square {
kind: "square",
geometry: {
side: number;
}
}
interface Circle {
kind: "circle",
geometry: {
radius: number;
}
}
interface Rectangle {
kind: "rectangle",
geometry: {
horizontalSide: number;
verticalSide: number;
}
}
interface Ellipsis {
kind: "ellipsis",
geometry: {
horizontalHalfAxis: number;
verticalHalfAxis: number;
}
}
// Union of all shapes
type Shape = Square | Circle | Rectangle | Ellipsis;
// Resolves to {square: Square, circle: Circle, rectangle: Rectangle, ellipsis: Ellipsis}
type kindToShape = UnionMap<Shape, "kind">;
An optional return type for functions that must either
explicitly return a value of a certain type; or not
have a return statement. Note that a function without
a return statement will return undefined
when called.
Contrast this with Maybe<T>
: Even if the return type
is declared as undefined
, the function must still contain
an explicit return undefined
statement.
interface UndoableAction {
perform(): Voidable<Promise<void>>;
undo(): Voidable<Promise<void>>;
}
The above interface defines an action that can be undone. An action never return a value, it only performs some side effects. It also supports asynchronous actions by returning a promise.
Generated using TypeDoc
Gives all property keys to which the given type can be assigned.
interface User { age: string | number; email: string | undefined; active?: boolean; } // A string can be assigned to the properties age and email. type userString = AssignableKeys<User, string>; // "age"|"email" // undefined can be assigned only to the properties email and active. type userUndefined = AssignableKeys<User, string>; // "email"|"active"