Skip to content

Instantly share code, notes, and snippets.

@phenomnomnominal
Forked from NeutralAngel/elsa.magic.ts
Last active April 3, 2020 02:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save phenomnomnominal/84e300d5de055298d505c4741281c2fd to your computer and use it in GitHub Desktop.
Save phenomnomnominal/84e300d5de055298d505c4741281c2fd to your computer and use it in GitHub Desktop.
type Freezable = {
unfreezable?: never; // Need to make the unfreezable property optional
};
type Frozen<T extends Freezable = Freezable> = T & {
frozen: true;
};
type Thawed<T> = T extends Frozen<infer R>
? R
: never;
function assertFreezable(thing: unknown): asserts thing is Freezable {
if (!thing || (thing as Freezable).unfreezable) {
throw new Error(`Can't freeze that! ❄️`);
}
}
function freeze<T extends Freezable = Freezable>(toFreeze: T): Frozen<T> {
assertFreezable(toFreeze);
(toFreeze as Frozen<T>).frozen = true;
return toFreeze as Frozen<T>;
}
function assertFrozen(thing: unknown): asserts thing is Frozen {
if (!thing || !(thing as Frozen).frozen) {
throw new Error(`Can't thaw that! ❄️`);
}
}
function thaw<T extends Frozen>(toThaw: T): Thawed<T> {
assertFrozen(toThaw);
delete toThaw.frozen;
return toThaw as Thawed<T>;
}
type Thing = Freezable & { thing: boolean }; // Need a type for the thing you're trying to freeze
freeze<Thing>({ thing: false, unfreezable: true }); // Not allowed
const frozenThing = freeze<Thing>({ thing: true });
const thawed = thaw(frozenThing);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment