ts-guardian
Version:
Declarative, composable type guards
252 lines (251 loc) • 11.8 kB
JavaScript
;
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.assertThat = exports.requireThat = exports.parserFor = exports.isSymbolOrUndefined = exports.isStringOrUndefined = exports.isNumberOrUndefined = exports.isNullOrUndefined = exports.isFunctionOrUndefined = exports.isBigintOrUndefined = exports.isBooleanOrUndefined = exports.isSymbolOrNull = exports.isStringOrNull = exports.isNumberOrNull = exports.isFunctionOrNull = exports.isBigintOrNull = exports.isBooleanOrNull = exports.isUndefined = exports.isSymbol = exports.isString = exports.isNumber = exports.isNull = exports.isFunction = exports.isBigint = exports.isBoolean = exports.isNullish = exports.isNullable = exports.isOptional = exports.isInstanceOf = exports.isLiterally = exports.isRecordOf = exports.isArrayOf = exports.is = void 0;
// Some functions imply a type (e.g. 'isArrayOf' implies an array).
// Internally, we store type defs as [impliedType, passedType].
// `passedType` is what the user provided; `impliedType` is inferred via a marker.
var arrayMarker = 'a';
var recordMarker = 'r';
var literalMarker = 'l';
var instanceMarker = 'i';
var andMarker = '&';
var anyGuard = function (_) { return true; };
var booleanGuard = function (v) { return typeof v === 'boolean'; };
var bigintGuard = function (v) { return typeof v === 'bigint'; };
var functionGuard = function (v) { return typeof v === 'function'; };
var nullGuard = function (v) { return v === null; };
var numberGuard = function (v) { return typeof v === 'number'; };
var objectGuard = function (v) { return typeof v === 'object'; };
var stringGuard = function (v) { return typeof v === 'string'; };
var symbolGuard = function (v) { return typeof v === 'symbol'; };
var undefinedGuard = function (v) { return v === undefined; };
var unknownGuard = function (_) { return true; };
var isLiteralTypeDef = function (t) { return Array.isArray(t) && t[0] === literalMarker; };
var literalGuard = function (_a, value) {
var _ = _a[0], t = _a.slice(1);
return t.includes(value);
};
var isInstanceTypeDef = function (t) { return Array.isArray(t) && t[0] === instanceMarker; };
var instanceGuard = function (_a, value) {
var _ = _a[0], t = _a[1];
return value instanceof t;
};
var isAndTypeDef = function (t) { return Array.isArray(t) && t[0] === andMarker; };
var andGuard = function (_a, value) {
var _ = _a[0], t = _a.slice(1);
return t.every(function (g) { return mainGuard(g, value); });
};
var isArrayTypeDef = function (t) { return Array.isArray(t) && t[0] === arrayMarker; };
var arrayGuard = function (_a, value) {
var _ = _a[0], t = _a[1];
return Array.isArray(value) && value.every(function (el) { return mainGuard(t, el); });
};
var tupleGuard = function (t, value) { return Array.isArray(value) && t.every(function (g, i) { return mainGuard(g, value[i]); }); };
var isRecordTypeDef = function (t) { return Array.isArray(t) && t[0] === recordMarker; };
var recordGuard = function (_a, value) {
var _ = _a[0], t = _a[1];
return typeof value === 'object' && value !== null && Object.values(value).every(function (v) { return mainGuard(t, v); });
};
var curlyObjectGuard = function (t, value) {
return typeof t === 'object' &&
t !== null &&
typeof value === 'object' &&
value !== null &&
Object.keys(t).every(function (k) { return mainGuard(t[k], value[k]); });
};
var mainGuard = function (t, value) {
try {
if (typeof t === 'string') {
if (t.endsWith('[]'))
return arrayGuard(['a', t.slice(0, -2)], value); // Basic array type
if (t.endsWith('?'))
return mainGuard(t.slice(0, -1), value) || undefinedGuard(value); // Basic optional type
// prettier-ignore
// Basic type
switch (t) {
case 'any': return anyGuard(value);
case 'boolean': return booleanGuard(value);
case 'bigint': return bigintGuard(value);
case 'function': return functionGuard(value);
case 'null': return nullGuard(value);
case 'number': return numberGuard(value);
case 'object': return objectGuard(value);
case 'string': return stringGuard(value);
case 'symbol': return symbolGuard(value);
case 'undefined': return undefinedGuard(value);
case 'unknown': return unknownGuard(value);
default: return false;
}
}
if (typeof t === 'function')
return t(value); // Guard
if (isArrayTypeDef(t))
return arrayGuard(t, value); // Array
if (isRecordTypeDef(t))
return recordGuard(t, value); // Record
if (isLiteralTypeDef(t))
return literalGuard(t, value); // Literal
if (isInstanceTypeDef(t))
return instanceGuard(t, value); // Instance
if (isAndTypeDef(t))
return andGuard(t, value); // And
if (Array.isArray(t))
return tupleGuard(t, value); // Tuple
return curlyObjectGuard(t, value); // Object
}
catch (_a) {
return false;
}
};
var createGuard = function (guardDefinitions) {
var guard = function (value) { return guardDefinitions.some(function (g) { return mainGuard(g, value); }); };
guard.or = createOr(guardDefinitions);
guard.orArrayOf = createOrArrayOf(guardDefinitions);
guard.orRecordOf = createOrRecordOf(guardDefinitions);
guard.orLiterally = createOrLiterally(guardDefinitions);
guard.orInstanceOf = createOrInstanceOf(guardDefinitions);
guard.and = createAnd(guardDefinitions);
return guard;
};
var createOr = function (prevTypeDefinitions) {
return function (t) {
return createGuard(__spreadArray(__spreadArray([], prevTypeDefinitions, true), [t], false));
};
};
var createAnd = function (prevTypeDefinitions) {
return function (t) {
var lastGuardDef = prevTypeDefinitions.slice(-1)[0];
return createGuard(__spreadArray(__spreadArray([], prevTypeDefinitions.slice(0, -1), true), [
Array.isArray(lastGuardDef) && lastGuardDef[0] === andMarker ? __spreadArray(__spreadArray([], lastGuardDef, true), [t], false) : [andMarker, lastGuardDef, t],
], false));
};
};
var createOrArrayOf = function (prevTypeDefinitions) {
return function (t) {
return createGuard(__spreadArray(__spreadArray([], prevTypeDefinitions, true), [[arrayMarker, t]], false));
};
};
var createOrRecordOf = function (prevTypeDefinitions) {
return function (t) {
return createGuard(__spreadArray(__spreadArray([], prevTypeDefinitions, true), [[recordMarker, t]], false));
};
};
var createOrLiterally = function (prevTypeDefinitions) {
return function () {
var t = [];
for (var _i = 0; _i < arguments.length; _i++) {
t[_i] = arguments[_i];
}
return createGuard(__spreadArray(__spreadArray([], prevTypeDefinitions, true), [__spreadArray([literalMarker], t, true)], false));
};
};
var createOrInstanceOf = function (prevTypeDefinitions) {
return function (t) {
return createGuard(__spreadArray(__spreadArray([], prevTypeDefinitions, true), [[instanceMarker, t]], false));
};
};
var is = function (t) { return createGuard([t]); };
exports.is = is;
var isArrayOf = function (t) { return createGuard([[arrayMarker, t]]); };
exports.isArrayOf = isArrayOf;
var isRecordOf = function (t) { return createGuard([[recordMarker, t]]); };
exports.isRecordOf = isRecordOf;
var isLiterally = function () {
var t = [];
for (var _i = 0; _i < arguments.length; _i++) {
t[_i] = arguments[_i];
}
return createGuard([__spreadArray([literalMarker], t, true)]);
};
exports.isLiterally = isLiterally;
var isInstanceOf = function (t) {
return createGuard([[instanceMarker, t]]);
};
exports.isInstanceOf = isInstanceOf;
var isOptional = function (t) { return createGuard([t, 'undefined']); };
exports.isOptional = isOptional;
var isNullable = function (t) { return createGuard([t, 'null']); };
exports.isNullable = isNullable;
var isNullish = function (t) { return createGuard([t, 'null', 'undefined']); };
exports.isNullish = isNullish;
/** @deprecated Use `is('boolean')` instead. */
exports.isBoolean = (0, exports.is)('boolean');
/** @deprecated Use `is('bigint')` instead. */
exports.isBigint = (0, exports.is)('bigint');
/** @deprecated Use `is('function')` instead. */
exports.isFunction = (0, exports.is)('function');
/** @deprecated Use `is('null')` instead. */
exports.isNull = (0, exports.is)('null');
/** @deprecated Use `is('number')` instead. */
exports.isNumber = (0, exports.is)('number');
/** @deprecated Use `is('string')` instead. */
exports.isString = (0, exports.is)('string');
/** @deprecated Use `is('symbol')` instead. */
exports.isSymbol = (0, exports.is)('symbol');
/** @deprecated Use `is('undefined')` instead. */
exports.isUndefined = (0, exports.is)('undefined');
/** @deprecated Use `isNullable('boolean')` instead. */
exports.isBooleanOrNull = (0, exports.isNullable)('boolean');
/** @deprecated Use `isNullable('bigint')` instead. */
exports.isBigintOrNull = (0, exports.isNullable)('bigint');
/** @deprecated Use `isNullable('function')` instead. */
exports.isFunctionOrNull = (0, exports.isNullable)('function');
/** @deprecated Use `isNullable('number')` instead. */
exports.isNumberOrNull = (0, exports.isNullable)('number');
/** @deprecated Use `isNullable('string')` instead. */
exports.isStringOrNull = (0, exports.isNullable)('string');
/** @deprecated Use `isNullable('symbol')` instead. */
exports.isSymbolOrNull = (0, exports.isNullable)('symbol');
/** @deprecated Use `is('boolean?')` instead. */
exports.isBooleanOrUndefined = (0, exports.is)('boolean?');
/** @deprecated Use `is('bigint?')` instead. */
exports.isBigintOrUndefined = (0, exports.is)('bigint?');
/** @deprecated Use `is('function?')` instead. */
exports.isFunctionOrUndefined = (0, exports.is)('function?');
/** @deprecated Use `is('null?')` instead. */
exports.isNullOrUndefined = (0, exports.is)('null?');
/** @deprecated Use `is('number?')` instead. */
exports.isNumberOrUndefined = (0, exports.is)('number?');
/** @deprecated Use `is('string?')` instead. */
exports.isStringOrUndefined = (0, exports.is)('string?');
/** @deprecated Use `is('symbol?')` instead. */
exports.isSymbolOrUndefined = (0, exports.is)('symbol?');
var parserFor = function (guard) {
return function (value) {
return guard(value) ? value : undefined;
};
};
exports.parserFor = parserFor;
var requireThat = function (value, guard, errorMessage) {
if (!guard(value)) {
if (errorMessage)
throw new TypeError(errorMessage);
var preview = void 0;
try {
preview = JSON.stringify(value);
}
catch (_a) {
try {
preview = String(value);
}
catch (_b) {
preview = '[unknown value]';
}
}
if (preview.length > 80)
preview = preview.slice(0, 77) + '...';
throw new TypeError("Type of '".concat(preview, "' does not match type guard."));
}
};
exports.requireThat = requireThat;
/** @deprecated Use requireThat instead */
exports.assertThat = exports.requireThat;