UNPKG

@rustable/type

Version:

A TypeScript implementation of Rust-like type system with generic support and runtime type information.

138 lines (136 loc) 3.67 kB
"use strict"; const typeMap = /* @__PURE__ */ new WeakMap(); const typeIdMap = /* @__PURE__ */ new WeakMap(); let i = 0; function typeId(target, genericParams) { if (target === null || target === void 0) { throw new Error("Cannot get typeId of null or undefined"); } const constructor = Type(type(target), genericParams); const existingId = typeIdMap.get(constructor); if (existingId !== void 0) { return existingId; } const id = `${++i}:${constructor.name}`; typeIdMap.set(constructor, id); return id; } const genericType = Symbol("GenericType"); function getGenericKey(genericParams) { return genericParams.map((param) => { return typeId(param); }).join(","); } function getGenericName(genericParams) { return genericParams.map((param) => { return param.name; }).join(","); } function Type(target, genericParams, newWithTypes = false) { validNull(target); if (genericParams && !Array.isArray(genericParams)) { throw new Error("Generic parameters must be an array"); } if (target[genericType]) { if (!genericParams || genericParams.length === 0) { return target; } else { throw new Error("Cannot specify generic parameters for generic type"); } } if (!genericParams || genericParams.length === 0) { return target.prototype.constructor; } const targetConstructor = target.prototype.constructor; let targetTypes = typeMap.get(targetConstructor); if (!targetTypes) { targetTypes = /* @__PURE__ */ new Map(); typeMap.set(targetConstructor, targetTypes); } const genericKey = getGenericKey(genericParams); let customType = targetTypes.get(genericKey); if (!customType) { customType = class extends targetConstructor { constructor(...args) { if (newWithTypes) { super(genericParams, ...args); } else { super(...args); } } }; Object.getOwnPropertyNames(targetConstructor).forEach((prop) => { if (prop !== "prototype" && prop !== "name") { Object.defineProperty(customType, prop, Object.getOwnPropertyDescriptor(targetConstructor, prop)); } }); const config = { writable: false, enumerable: false, configurable: false }; Object.defineProperties(customType, { name: { value: `${targetConstructor.name}<${getGenericName(genericParams)}>`, ...config }, [genericType]: { value: true, ...config }, generics: { value: genericParams, ...config } }); targetTypes.set(genericKey, customType); } return customType; } function isGenericType(target) { validNull(target); return target[genericType] === true; } function getGenerics(target) { if (!isGenericType(target)) { return []; } return target.generics || []; } function typeName(target) { validNull(target); if (typeof target === "function") { return target.name; } else { return target.constructor.name; } } function type(target) { validNull(target); if (typeof target === "function") { return target; } else { return target.constructor; } } function validNull(target) { if (target === null) { throw new Error("Cannot get type of null"); } if (target === void 0) { throw new Error("Cannot get type of undefined"); } } function named(name, target) { const n = function(t) { Object.defineProperty(t, "name", { value: name, writable: false, enumerable: false, configurable: true }); return t; }; return target ? n(target) : n; } export { Type, getGenerics, isGenericType, named, type, typeId, typeName };