ts-prims
Version:
Typescript Primitives
109 lines • 4.16 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Prim = exports.constraintsOf = exports.primTypeOf = exports.superConstraint = exports.display = void 0;
/**
* Returns a 'display value' string for `v`.
*
* In case `v` is of type `string`, the returned string will be `v` within
* double quotes. Otherwise it will return the result of the built-in to-string
* happening naturally when appending primitives to strings in Javascript.
*
* ```ts
* display('Hello, World!') // '"Hello, World"'
* display(2 + 5) // '7'
* ```
*
* @param v The primitive-typed value
* @returns The display value string of `v`
*/
const display = (v) => typeof v == 'string' ?
`"${v}"` :
`${v}`;
exports.display = display;
/**
* Constraint that the primitive type of two types must be equal for them to be
* assignable to one another. This constraint is implied in the type system and
* made explicit in the runtime implementation through this object.
*/
const superConstraint = (pc, v) => typeof v == (0, exports.primTypeOf)(pc) ? undefined :
`${(0, exports.display)(v)} is not assignable to type '${pc.name}'.\n` +
` Supertypes do not match: ${typeof v}, ${(0, exports.primTypeOf)(pc)}.`;
exports.superConstraint = superConstraint;
/**
* Returns the underlying type of the given constructor function `pc`.
*
* This is basically a version of `typeof` that operates, not directly on the
* values, but on the constructor function itself.
*
* @template P The primitive type
* @param pc The prim constructor
* @returns The underlying type of `pc`: `'boolean'`, `'string'`,
* `'number'` or `'bigint'`.
*/
const primTypeOf = (pc) => 'super' in pc ? (0, exports.primTypeOf)(pc.super) :
pc === Boolean ? 'boolean' :
pc === String ? 'string' :
pc === Number ? 'number' :
'bigint';
exports.primTypeOf = primTypeOf;
/** Gets the constraints associated with the constructor `pc` */
const constraintsOf = (pc) => 'super' in pc ? pc.constraints : [exports.superConstraint];
exports.constraintsOf = constraintsOf;
/**
* Creates a constructor function for a primitive type extending `P`.
*
* Whenever your type requires runtime presence, the `Prim` function can be
* used to create a constructor function for your primitive type, following
* the same pattern:
*
* ```ts
* import { type prim, type width, Prim, widthConstraint } from 'ts-prims'
* // use the `width` type to constrain the width of `byte`
* type byte = prim<number, width<1>>
* // use the `widthConstraint` to constrain the width at runtime
* const Byte = Prim<byte>('byte', Number, widthConstraint(1))
* let x: byte = Byte(100) // ok
* let y: byte = Byte(1000) // runtime error
* // TypeError: 1000 is not assignable to 'byte': -128 .. 127
* ```
*
* @template P The primitive type
*
* @param name The name for the type, e.g. `int`
* @param pc The parent constructor function, e.g. `Int` or `Number`
* @param constraints Optional constraints for the primitive type. Any
* constraints from the super constructor will be used automatically
* and should not be passed in here again.
*
* @see {@link PrimFactory}
* @see {@link PrimConstructor}
* @see {@link NativeConstructor}
* @see {@link Constraint}
*/
const Prim = (name, pc, constraints = []) => {
const result = ({ [name]: (v) => result.to(v) })[name];
result.super = pc;
constraints =
Array.isArray(constraints) ? constraints :
constraints ? [constraints] : [];
result.constraints = [...(0, exports.constraintsOf)(pc), ...constraints];
result.is = (v) => {
for (let constraint of result.constraints) {
const err = constraint(result, v);
if (err)
return false;
}
return true;
};
result.as = (v) => {
for (let constraint of result.constraints) {
const err = constraint(result, v);
if (err)
throw new TypeError(err);
}
};
result.to = (v) => { result.as(v); return v; };
return result;
};
exports.Prim = Prim;
//# sourceMappingURL=prim.js.map