Pretty much like with JSDoc @typedef one can declare a custom type and use it as a contract.
Validating against a Union Type
Here we define a union type for values that can contain either numbers or strings that represent numbers.
Copy import { validate , typedef } from "bycontract" ;
typedef ( "NumberLike" , "number|string" );
validate ( 10 , "NumberLike" ); // OK
validate ( null , "NumberLike" ); // ByContractError: expected number|string but got null
Validating against a Complex Type
This example defines a type #Hero
that represents an object/namespace required to have properties hasSuperhumanStrength
and hasWaterbreathing
both of boolean type.
Copy import { validate , typedef } from "bycontract" ;
typedef ( "#Hero" , {
hasSuperhumanStrength : "boolean" ,
hasWaterbreathing : "boolean"
});
var superman = {
hasSuperhumanStrength : true ,
hasWaterbreathing : false
};
validate ( superman , "#Hero" ); // OK
Custom type in the example above is prefixed with sharp (#) to avoid interfering with global objects. It's not required though.
When any of properties violates the specified contract an exception thrown
Copy var superman = {
hasSuperhumanStrength : 42 ,
hasWaterbreathing : null
};
validate ( superman , "#Hero" );
// ByContractError: property #hasSuperhumanStrength expected boolean but got number
If value misses a property of the complex type an exception thrown
Copy var auqaman = {
hasWaterbreathing : true
};
validate ( superman , "#Hero" );
// ByContractError: missing required property #hasSuperhumanStrength
Custom Types and modifiers
Custom type is treated the same way as any other type in JSDoc
Copy typedef ( "#Hero" , {
hasSuperhumanStrength : "boolean" ,
hasWaterbreathing : "boolean"
});
validate ( { foo : superman } , "Object.<string, #Hero>" );
validate ( "text" , "string|#Hero" );
validate ( [ superman ] , "#Hero[]" );
validate ( null , "?#Hero" );
validate ( false , "#Hero=" );