45 lines
1.2 KiB
TypeScript
45 lines
1.2 KiB
TypeScript
|
|
/**
|
||
|
|
* Used by Flavor to mark a type in a readable way.
|
||
|
|
*/
|
||
|
|
export interface Flavoring<FlavorT> {
|
||
|
|
_type?: FlavorT;
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
*
|
||
|
|
* Create a "flavored" version of a type. TypeScript will disallow mixing
|
||
|
|
* flavors, but will allow unflavored values of that type to be passed in where
|
||
|
|
* a flavored version is expected. This is a less restrictive form of branding.
|
||
|
|
*
|
||
|
|
*/
|
||
|
|
export type Flavor<T, FlavorT> = T & Flavoring<FlavorT>;
|
||
|
|
|
||
|
|
export type UUID = Flavor<string, "A UUID">;
|
||
|
|
|
||
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||
|
|
export const deepFreeze = (o: unknown): any => {
|
||
|
|
Object.freeze(o);
|
||
|
|
|
||
|
|
const oIsFunction = typeof o === "function";
|
||
|
|
const hasOwnProp = Object.prototype.hasOwnProperty;
|
||
|
|
|
||
|
|
Object.getOwnPropertyNames(o).forEach((prop) => {
|
||
|
|
if (
|
||
|
|
hasOwnProp.call(o, prop) &&
|
||
|
|
(oIsFunction
|
||
|
|
? prop !== "caller" && prop !== "callee" && prop !== "arguments"
|
||
|
|
: true) &&
|
||
|
|
// @ts-expect-error
|
||
|
|
o[prop] !== null &&
|
||
|
|
// @ts-expect-error
|
||
|
|
(typeof o[prop] === "object" || typeof o[prop] === "function") &&
|
||
|
|
// @ts-expect-error
|
||
|
|
!Object.isFrozen(o[prop])
|
||
|
|
) {
|
||
|
|
// @ts-expect-error
|
||
|
|
deepFreeze(o[prop]);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
return o;
|
||
|
|
};
|