вторник, 18 октября 2016 г.

JavaScript Type.js - How to check type in runtime

Файл type.js

/*
Примеры:

type.String(1, 'Wrong value.');

var a = type.func(
      [type.Number, type.String], type.Object
    , function (a, b) {
        return {
            a: a
          , b: b
        };
    }
);

a(1, 2);

type.add('Password', function (value, message) {
    if (not (typeof value === 'string' && value.length > 6)) {
        if (message) {
            throw new Error(message);
        } else {
            throw new Error('Type of value ' + value + ' must be password, but it has type ' + Object.prototype.toString.call(value).slice(8, -1).toLowerCase() + '.');
        }
    }
});

type.Password(1, 'Wrong value.');

var point = type.obj(
      {
          x: type.Number
        , y: type.Number
      }
    , {
          x: 1
        , y: '2'
    }
);

var list = type.arr(
      [type.Number, type.String, type.Object] // или просто type.Number для всех значений
    , [1, '2', {a: 3}]
);

*/

function not (bool) {return !bool;}

var type = {};

type.add = function (name, predicate) {
    if (name in type) {throw new Error('Type ' + name + ' already defined.');}
    type[name] = predicate;
};

type.alias = function (name, typeFunction) {
    if (name in type) {throw new Error('Type ' + name + ' already defined.');}
    type[name] = typeFunction;
}

type.func = function (argumentTypesArray, returnValueType, functionBody) {
    return function () {
        for (var i = 0, len = argumentTypesArray.length; i < len; i++) {
            argumentTypesArray[i](arguments[i]);
        }
        var result = functionBody.apply(null, arguments);
        returnValueType(result);
        return result;
    };
};

type.obj = function (types, object) {
    for (var key in types) {
        if (Object.prototype.hasOwnProperty.call(types, key)) {
            if (not (Object.prototype.hasOwnProperty.call(object, key))) {
                throw new Error('Object don\'t have key ' + key + '.');
            } else {
                types[key](object[key]);
            }
        }
    }
    return object;
};

type.arr = function (types, array) {
    var typesIndex = 0
        , arrayIndex = 0
        , typesLength
        , arrayLength = array.length;
    if (Object.prototype.toString.call(types) === '[object Array]') {
        for (typesLength = types.length; typesIndex < typesLength; typesIndex++, arrayIndex++) {
            types[typesIndex](array[arrayIndex]);
        }
    } else if (typeof types === 'function') {
        for (; arrayIndex < arrayLength; arrayIndex++) {
            types(array[arrayIndex]);
        }
    }
    return array;
};

type.Any = function () {
    // can be any value
};

type.Undefined = function (value, message) {
    if (not (value === void 0)) {
        if (message) {
            throw new Error(message);
        } else {
            throw new Error('Type of value ' + value + ' must be undefined, but it has type ' + Object.prototype.toString.call(value).slice(8, -1).toLowerCase() + '.');
        }
    }
};

type.Null = function (value, message) {
    if (not (value === null)) {
        if (message) {
            throw new Error(message);
        } else {
            throw new Error('Type of value ' + value + ' must be null, but it has type ' + Object.prototype.toString.call(value).slice(8, -1).toLowerCase() + '.');
        }
    }
};

type.Nil = function (value, message) {
    if (not (value === void 0 || value === null)) {
        if (message) {
            throw new Error(message);
        } else {
            throw new Error('Type of value ' + value + ' must be undefined or null, but it has type ' + Object.prototype.toString.call(value).slice(8, -1).toLowerCase() + '.');
        }
    }
};

type.Boolean = function (value, message) {
    if (not (value === true || value === false)) {
        if (message) {
            throw new Error(message);
        } else {
            throw new Error('Type of value ' + value + ' must be boolean, but it has type ' + Object.prototype.toString.call(value).slice(8, -1).toLowerCase() + '.');
        }
    }
};

type.Number = function (value, message) {
    if (not (typeof value === 'number' && value === value && isFinite(value))) {
        if (message) {
            throw new Error(message);
        } else {
            throw new Error('Type of value ' + value + ' must be number, but it has type ' + Object.prototype.toString.call(value).slice(8, -1).toLowerCase() + '.');
        }
    }
};

type.String = function (value, message) {
    if (not (typeof value === 'string')) {
        if (message) {
            throw new Error(message);
        } else {
            throw new Error('Type of value ' + value + ' must be string, but it has type ' + Object.prototype.toString.call(value).slice(8, -1).toLowerCase() + '.');
        }
    }
};

type.Array = function (value, message) {
    if (not (Object.prototype.toString.call(value) === '[object Array]')) {
        if (message) {
            throw new Error(message);
        } else {
            throw new Error('Type of value ' + value + ' must be array, but it has type ' + Object.prototype.toString.call(value).slice(8, -1).toLowerCase() + '.');
        }
    }
};

type.Object = function (value, message) {
    if (not (Object.prototype.toString.call(value) === '[object Object]')) {
        if (message) {
            throw new Error(message);
        } else {
            throw new Error('Type of value ' + value + ' must be object, but it has type ' + Object.prototype.toString.call(value).slice(8, -1).toLowerCase() + '.');
        }
    }
};

type.Function = function (value, message) {
    if (not (typeof value === 'function')) {
        if (message) {
            throw new Error(message);
        } else {
            throw new Error('Type of value ' + value + ' must be function, but it has type ' + Object.prototype.toString.call(value).slice(8, -1).toLowerCase() + '.');
        }
    }
};

type.Date = function (value, message) {
    if (not (value instanceof Date)) {
        if (message) {
            throw new Error(message);
        } else {
            throw new Error('Type of value ' + value + ' must be date, but it has type ' + Object.prototype.toString.call(value).slice(8, -1).toLowerCase() + '.');
        }
    }
};

type.RegExp = function (value, RegExp) {
    if (not (value instanceof Date)) {
        if (message) {
            throw new Error(message);
        } else {
            throw new Error('Type of value ' + value + ' must be regular expression, but it has type ' + Object.prototype.toString.call(value).slice(8, -1).toLowerCase() + '.');
        }
    }
};

type.Error = function (value, message) {
    if (not (value instanceof Error)) {
        if (message) {
            throw new Error(message);
        } else {
            throw new Error('Type of value ' + value + ' must be error, but it has type ' + Object.prototype.toString.call(value).slice(8, -1).toLowerCase() + '.');
        }
    }
};

Комментариев нет:

Отправить комментарий