Utilities
equals
equals compares two Vals of the same type structurally and deeply:
import { equals, Val } from "valof";
type User = Val<"User", { id: string; profile: { name: string } }>;
const User = Val.sealer<User>();
const a = User({ id: "a", profile: { name: "alice" } });
const b = User({ id: "a", profile: { name: "alice" } });
a === b; // false
equals(a, b); // true
The comparison:
- compares array elements in order
- is independent of object key order
- ignores keys whose value is
undefined({ a: undefined }equals{}) - treats
NaNas equal toNaN, and-0as equal to0
The first argument fixes the Val type accepted by the second, so comparing values with different brands is a type error.
equals always compares the stored structure. When different inputs mean the same value, normalize
them in the seal. When the comparison means
something other than value equality, give it a name in the companion.
Val.of
Brands a payload with the type named explicitly.
Val.of<User>({ id: "a", name: "alice" });
If the type has a seal of its own, use that instead. Val.of skips the checks as an escape
hatch. Linting reports misuse of it, such as calling Val.of on a type that has a
companion or specifying no type.
Val.unwrap
A plain, mutable deep copy of the payload, to pass to code that does not know about readonly. It
strips the brand at every depth.
const post = Post({ title: "t", tags: ["a"] });
post.tags.sort(); // ✗ readonly string[] has no sort
Val.unwrap(post).tags.sort(); // ✓
It returns the payload as the type declares it, so a readonly written there survives the unwrap.
Write the payload plain. See Allowed types.