Skip to content

Instantly share code, notes, and snippets.

@Pho3nixHun
Last active March 28, 2018 08:55
Show Gist options
  • Save Pho3nixHun/b625feda67f2862285a330ea2cd47eed to your computer and use it in GitHub Desktop.
Save Pho3nixHun/b625feda67f2862285a330ea2cd47eed to your computer and use it in GitHub Desktop.
Will throw a TypeError if definition does not match with target.

Examples for Usage

expect(def, data)

Purpose

Check variables against a definitions. If it doesn't mach throw a type error with a helpful message to see what is wrong.

Parameters

def

  • Can be a string where value of the string is the type that target needs to have.
  • Can be a number or a boolean where value of def will have to match with the value of target.
  • Can be an Array with one item of any type in this list. Target have to be an array with all items in it matching with that definition.
  • Can be an Object with mandatory field definitions where key is the name of that field and value of key should be any type in this list.

target Target to match against to definition

Example code

const ds = {
    screenLayout: 'layout-1',
    treatment: 'url',
    items: [1, '2', false],
    gridLink: {
        id: 'id',
        type: 'type-1'
    },
    synopsis: 'You should check these out!'
}
const definition = {
    screenLayout: 'String',
    background: 'String',
    items: ['Number|String'],
    gridLink: {
        id: 'String',
        type: 'String'
    }
};
expect(definition, data);

/* Throws TypeError 
Target expected to match with {
    "screenLayout": "String",
    "background": "String <- Mismatch here Target expected to be String but it is undefined",
    "items": [
        "Number|String"
    ],
    "gridLink": {
        "id": "String",
        "type": "String"
    }
} but it is {
    "screenLayout": "layout-1",
    "treatment": "url",
    "items": [
        1,
        "2",
        false
    ],
    "gridLink": {
        "id": "id",
        "type": "type-1"
    },
    "synopsis": "You should check these out !"
}

If you fix that it will throw TypeError again:
Target expected to have {
    "screenLayout": "String",
    "items": "Number|String <- Mismatch here Target expected to be Array<of Number|String> but at index 2 it is boolean",
    "gridLink": {
        "id": "String",
        "type": "String"
    }
} but it is {
    "screenLayout": "layout-1",
    "treatment": "url",
    "items": [
        1,
        "2",
        false
    ],
    "gridLink": {
        "id": "id",
        "type": "type-1"
    },
    "synopsis": "You should check these out !"
}

*/
/**
* Will throw a TypeError if definition does not match with target.
* @param {string} def The types to chec target against. Multiple types have to be separated by | (pipe).
* @param {Object.<string, string|Object|Array|number|boolean>} def The object of definitions the target object will be matched against.
* @param {[string|Object|Array|number|boolean]} def Target Array(!) will be matched against def[0].
* @param {number|boolean} def Target's value will be matched against the value of definition.
* @param {any} target Target to check.
* @example See shared/Utils.md
*/
function expect(def, target) {
const defType = get(def, 'constructor.name', typeof def);
const targetType = get(target, 'constructor.name', typeof target);
switch (defType) {
case 'String':
case 'string':
if (!def.split('|').includes(targetType)) {
throw new TypeError(`Target expected to be ${def} but it is ${targetType}`);
}
return true;
case 'object':
case 'Object':
if (targetType !== 'Object') {
throw TypeError(`Target expected to be Object but it is ${targetType}`);
}
return Object.keys(def).every((key) => {
try {
expect(def[key], target[key]);
} catch (ex) {
const report = Object.assign({}, def, { [key]: `${def[key]} <- Mismatch here ${ex.message}` });
throw new TypeError(`Target expected to match with ${JSON.stringify(report, null, 4)} but it is ${JSON.stringify(target, null, 4)}`);
}
return true;
});
case 'Array':
if (targetType !== 'Array') {
throw TypeError(`Target expected to be Array<of ${def[0]}> but it is ${targetType}`);
}
return target.every((item, index) => {
try {
expect(def[0], item);
} catch (ex) {
throw TypeError(`Target expected to be Array<of ${def[0]}> but at index ${index} it is ${get(item, 'constructor.name', typeof item)}`);
}
return true;
});
case 'number':
case 'Number':
case 'boolean':
case 'Boolean':
if (def === target) {
throw new TypeError(`Target expected to be ${def} but it is ${target}`);
}
return true;
case 'undefined':
default:
throw new TypeError('def expected to be defined');
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment