0.9.8 • Published 8 years ago

safejs v0.9.8

Weekly downloads
3
License
Apache-2.0
Repository
github
Last release
8 years ago

safejs

DEPRECATION WARNING

WARNING: This project has been renamed to typesafe. Install using npm install typesafe instead.

NPM

This JavaScript library provides the ability to perform automatic runtime type checking on function parameters and function polymorphism.

Documentation

Run grunt docs inside the project root directory to generate API docs for all properties of the ts object.

Table of contents

ts.func

The ts.func method will wrap the function passed to it in a TypeSafeFunction that will check the type of its parameters before running the passed in method.

Syntax

func(params, method[, context, methodName]) → {TypeSafeFunction}

Parameters

  • params: An object or array containing the type definitions of each parameter that will be type checked (in the order they appear in the method).

    • Array notation: [ <Type Definition>, ... ]
    • Object notation: { <Parameter Name>: <Type Definition>, ... }
    • See below for defining type definitions
  • method: The method whose parameter types should be checked with the passed in type definitions.

  • context (Optional): The value to use as this when executing the method.
  • methodName (Optional): The method name to display in any invalid type error messages that are thrown.

Returns

A TypeSafeFunction that will check the types of its parameters before executing method.

Example

var myFunction = ts.func({
    param1: ts.isString
}, function(param1) {
    console.log("I ran!"); 
}, null, 'myFunctionName');

myFunction('a');
> 'I ran!'

myFunction(1);
> 'TypeDefinitionError: [myFunctionName] Error: Object "param1" with value: 1 has an invalid type. Please check the "typeDefinition" property to check valid types and attributes.'

Returning errors instead of throwing them

Normally when an invalid type is passed into a TypeSafeFunction the function will throw a TypeDefinitionError stating the parameter name/index of the parameter that did not meet its type definition, the type definition the parameter represents and the value of the parameter. To return a TypeDefinitionError instead of throwing one, set the throwable property of the TypeSafeFunction to false. e.g.

var myFunction = ts.func([ts.isString], function(param1) {
    ...
});

myFunction.throwable = false;

To make all TypeSafeFunctions returned by func return the error instead of throwing, set the throwable property of the ts.func method to false, e.g.

ts.func.throwable = false;

This will make all future TypeSafeFunctions returned by func not throw (previous TypeSafeFunctions created before setting the property will perform the default action).

Passing Type Definitions

Types for this library are represented using methods which act as type checkers. A method checking for a particular type will accept a single parameter and return either true or false if the value passed in matches with the type it is representing or not (note: truthy and falsey values won't always work!).

The ts object by default provides many different type checkers to check for primitive types (i.e. ts.isString, ts.isNumber, etc.). See the wiki for a full list of type checkers provided by the library.

Single Types

To check for single types, simply pass in a single type checker for the parameters. e.g.

var myFunction = ts.func({
    param1: ts.isString
}, function() {
    ...
});

In the above example, myFunction will only execute the method passed in if the first parameter, param1, is a string.

Multiple Types

To allow parameters to be one of multiple types, pass in multiple type checkers in an array for the parameter. e.g.

var myFunction = ts.func({
    param1: [ts.isString, ts.isInstanceOf(MyCustomClass)]
}, function() {
    ...
});

In the above example, myFunction will only execute the method passed in if the first parameter, param1, is either a string or an instance of the MyCustomClass class.

Types inside arrays

To check for the type of values inside an array, nest the type checkers inside an array, e.g.

var myFunction = ts.func({
    param1: [[ts.isString], [ts.isNumber]]
}, function() {
    ...
});

In the above example, myFunction will only execute the method passed in if the first parameter, param1, is either an array of strings or an array of numbers. To allow an array containing either strings or numbers, nest both type checkers inside a single array, e.g.

var myFunction = ts.func({
    param1: [[ts.isString, ts.isNumber]]
}, function() {
    ...
});

You can nest the type checkers in as many arrays as you like (for example to check for an array of an array of strings, pass in: [[[ts.isString]]]), but since this library performs type checking at runtime, excessive nesting will affect performance.

Attributes

Sometimes you want to perform additional checks to a parameter that doesn't involve types. For example if one of your parameters is an array, you might want to ensure that the array is not empty. Passing in a "not empty" type checker would not work since only one type checker has to pass for a value for it to be considered valid.

Attributes allow parameters to pass any additional tests to be considered valid. To pass in an attribute, place the type checkers in a type property inside an object and attributes in an attr property inside the same object and pass that object to func instead. e.g.

var myFunction = ts.func({
    param1: {
        types: [[ts.isString]],
        attr: ts.isNot(ts.isEmpty)
    }
}, function() {
    ...
});

In the above example, myFunction will only execute the method passed in if the first parameter, param1, is an array of strings that is not empty.

Just like with types, multiple attributes can be passed in inside an array and attributes can be further nested inside arrays if you wish for them to be applied to the elements inside an array.

Saving Types

The examples of types mentioned above ultimately get converted by func into instances of the ts.TypeDefinition class. Therefore, instances of that class can be passed in to func as well. The constructor of the class takes in any of the examples of types mentioned above.

An example use case for this might be if you have a specific type definition that is too long and would like to be applied to multiple methods. An instance of the ts.TypeDefinition class can be created and passed instead so that the type definition does not have to be re-entered multiple times, e.g.

var myTypeDef = new ts.TypeDefnition({
    types: [[ts.isString], [ts.isNumber], ts.isInstanceOf(MyClass)],
    attr: ts.isNot(ts.isEmpty)
});

var myFunction1 = ts.func({
    param1: myTypeDef
}, function(param1) {
    ...
});

var myFunction2 = ts.func([myTypeDef], function(param1) {
    ...
});

The above example creates an instance of a TypeDefinition called myTypeDef, which defines a particular type. This type will allow either an array of strings, an array of numbers or any instances of the MyClass object. The value must also not be empty (note that this attribute applies not only to arrays, but to objects as well).

myTypeDef is then passed in to ts.func twice to create two separate functions, myFunction1 and myFunction2, both of which check to ensure that the first parameter matches the type defined by typeDef.

In the case of myFunction2, the array form for passing in type definitions was used, see below for for more details about the differences between the array and object notations.

####Allowing null and undefined (for users upgrading from v.0.9.6) For versions 0.9.6 and below, there were additional allowNull and allowUndefined properties that could be passed in as well. To have the same behaviour for versions 0.9.7 and above, pass in the ts.isNull and ts.isUndefined type checkers for the parameter. Note that the ts.isObject type checker returns false for functions and null objects.

####Array vs. Object Notation for passing in type definitions

Type definitions for individual parameters can be passed into the func method as either objects or arrays. The object notation (used in the examples above) is an object where the keys are the parameter names and values the type definitions (as either methods, array of methods, objects or instances of the ts.TypeDefinition class). An example of the object notation would be:

var myFunction = ts.func({
	param1: [[ts.isString]]

}, function(param1) {
    ...
});

Using the object notation lets func know the names of the parameters being used in the passed in method and can therefore use them in error messages when an invalid type is passed in.

There is also an array notation to represent type definitions to make creating functions from ts.func seem less intrusive. The array version is basically all the values of the object in the object notation. The above example represented using array notation would be:

var myFunction = ts.func([[[ts.isString]]], function(param1) {
    ...
});

The tradeoff with this method is that the error messages will only provide the index of the parameter that did not follow its type definition rather than the name of the parameter.

ts.poly

The ts.poly method will wrap multiple functions passed to it along with the type definitions for their parameters and will return a PolyFunction which will run the appropriate function based on the types of the parameters passed in. Basically this method attempts to emulate function polymorphism for JavaScript.

Syntax

poly(<params, method[, context, methodName]>*) → {PolyFunction}

Parameters

  • params: An object or array containing the type definitions of each parameter that will be type checked (in the order they appear in the method).

    • Array notation: [ <Type Definition>, ... ]
    • Object notation: { <Parameter Name>: <Type Definition>, ... }
  • method: The method whose parameter types should be checked with the passed in type definitions.

  • context (Optional): The value to use as this when executing the method.
  • methodName (Optional): The method name to display in any invalid type error messages that are thrown.

The above four parameters can be passed in multiple times for each method, e.g.

var myFunction = ts.poly([ts.isString], method1, context, "name", 
                        [ts.isNumber, method1, context, "name2"], 
                        ...);

See above for how to represent type definitions.

Returns

A PolyFunction that will check the types of its parameters and execute the appropriate method.

Example

var myFunction = ts.poly({
    param1: ts.isString
}, function(param1) {
    console.log("String version!"); 
}, null, null, 

{
    param1: ts.isNumber
}, function(param1) {
    console.log("Number version!");
});

myFunction.add([ts.isArray], function(param1) {
    console.log("Array version!");
});

myFunction('a');
> 'String version!'

myFunction(1);
> 'Number version!'

myFunction([]);
> 'Array version!'

myFunction(new Date());
> 'TypeDefinitionError: Error: Object "0" with value: Sat Dec 26 2015 23:04:56 GMT-0500 (EST) has an invalid type. Please check the "typeDefinition" property to check valid types and attributes.'

###Adding additional methods Although multiple methods can be added when running ts.poly, additional methods can be added after the PolyFunction is created by calling the add function of the returned PolyFunction. e.g.

var myFunction = ts.poly([ts.isString], function(param1) {
    ...
});

myFunction.add([ts.isNumber], function(param1) {
    ...
});

Returning errors instead of throwing them

Normally when an invalid type is passed into a PolyFunction the function will throw a TypeDefinitionError stating the parameter name/index of the parameter of its last method that did not meet its type definition, the type definition the parameter represents and the value of the parameter. To return a TypeDefinitionError instead of throwing one, set the throwable property of the PolyFunction to false. e.g.

var myFunction = ts.poly([ts.isString], function(param1) {
    ...
});

myFunction.throwable = false;

To make all PolyFunctions returned by poly return the error instead of throwing, set the throwable property of the ts.poly method to false, e.g.

ts.poly.throwable = false;

This will make all future PolyFunctions returned by poly not throw (previous PolyFunctions will).

Running as a browser library

The latest versions of the library are be under the dist folder.

Building

  1. Run npm install inside the root directory
  2. Run grunt inside the root directory to build typesafe as a browser library.
  3. The built files will be in the dist folder.

Compatibility

Browser compatibility was checked using JavaScript Compatibility Checker.

Desktop

IEChromeFirefoxOperaSafari
9+5+4+12+5.0+

Mobile

Opera MiniiOS SafariAndroid
5.0+3.2+4.4.3+

Tests

Tests are located in the tests/lib directory of the project. Run grunt test to run a linter (JSHint) and all tests.

License

This library is licenced under the Apache License v.2.

0.9.8

8 years ago

0.9.5

9 years ago

0.9.4

9 years ago

0.9.3

9 years ago

0.9.2

9 years ago

0.9.1

9 years ago

0.9.0

9 years ago