Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions packages/entity/src/base.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ abstract class AccountBase extends Entity.abstract("Account")(
{
immutable: ["id"],
computed: {
shout: Entity.computed(Upper, (d) => d.label.toUpperCase() as z.infer<typeof Upper>),
shout: Entity.computed(Upper, (d) => d.label.toUpperCase()),
},
invariants: [Entity.invariant((d) => d.label.length <= 20, "label must be at most 20 chars")],
},
Expand Down Expand Up @@ -181,7 +181,7 @@ test("a variant declaring computed keeps the root's", () => {
{ note: Label },
{
computed: {
murmur: Entity.computed(Label, (d) => d.label.toLowerCase() as z.infer<typeof Label>),
murmur: Entity.computed(Label, (d) => d.label.toLowerCase()),
},
},
) {
Expand Down Expand Up @@ -289,7 +289,7 @@ test("a variant redefining one computed key overrides that entry only", () => {
{ note: Label },
{
computed: {
shout: Entity.computed(Upper, (d) => `${d.label}!`.toUpperCase() as z.infer<typeof Upper>),
shout: Entity.computed(Upper, (d) => `${d.label}!`.toUpperCase()),
},
},
) {
Expand Down
4 changes: 2 additions & 2 deletions packages/entity/src/base.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ abstract class AccountBase extends Entity.abstract("Account")(
{
immutable: ["id"],
computed: {
shout: Entity.computed(Upper, (d) => d.label.toUpperCase() as z.infer<typeof Upper>),
shout: Entity.computed(Upper, (d) => d.label.toUpperCase()),
},
},
) {
Expand Down Expand Up @@ -119,7 +119,7 @@ test("a redefined computed key takes the variant's type, not an intersection", (
{ note: Label },
{
computed: {
shout: Entity.computed(Label, (d) => d.label.toLowerCase() as z.infer<typeof Label>),
shout: Entity.computed(Label, (d) => d.label.toLowerCase()),
},
},
) {
Expand Down
19 changes: 5 additions & 14 deletions packages/entity/src/computed.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,8 @@ class Person extends Entity("Person")(
{
immutable: ["id"],
computed: {
fullName: Entity.computed(
FullName,
(d) => `${d.first} ${d.last}` as z.infer<typeof FullName>,
),
initials: Entity.computed(
Initials,
(d) => `${d.first[0]}${d.last[0]}` as z.infer<typeof Initials>,
),
fullName: Entity.computed(FullName, (d) => `${d.first} ${d.last}`),
initials: Entity.computed(Initials, (d) => `${d.first[0]}${d.last[0]}`),
},
},
) {}
Expand Down Expand Up @@ -107,10 +101,7 @@ test("an invariant constrains a computed value through its sources", () => {
{ id: PersonId, first: NamePart, last: NamePart },
{
computed: {
fullName: Entity.computed(
FullName,
(d) => `${d.first} ${d.last}` as z.infer<typeof FullName>,
),
fullName: Entity.computed(FullName, (d) => `${d.first} ${d.last}`),
},
invariants: [
Entity.invariant(
Expand All @@ -137,7 +128,7 @@ test("computed output failing its own schema is a defect, not bad input", () =>
{
// FullName requires at least 1 char; this returns an empty string
computed: {
fullName: Entity.computed(FullName, () => "" as z.infer<typeof FullName>),
fullName: Entity.computed(FullName, () => ""),
},
},
) {}
Expand Down Expand Up @@ -165,7 +156,7 @@ test("a defect names the field that produced it", () => {
{ id: PersonId, first: NamePart, last: NamePart },
{
computed: {
initials: Entity.computed(Initials, () => "" as z.infer<typeof Initials>),
initials: Entity.computed(Initials, () => ""),
},
},
) {}
Expand Down
5 changes: 1 addition & 4 deletions packages/entity/src/contract.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,7 @@ class ApiKey extends Entity("ApiKey")(
// a denormalised field: stored so a query can index it, re-derived on
// every construction so it cannot drift from `label`
computed: {
searchKey: Entity.computed(
SearchKey,
(d) => d.label.toLowerCase() as z.infer<typeof SearchKey>,
),
searchKey: Entity.computed(SearchKey, (d) => d.label.toLowerCase()),
},
},
) {}
Expand Down
19 changes: 10 additions & 9 deletions packages/entity/src/entity.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ test("an invariant sees the declared fields, never a computed one", () => {
{ id: OrgId, slug: Slug },
{
computed: {
shout: Entity.computed(Upper, (d) => d.slug.toUpperCase() as z.infer<typeof Upper>),
shout: Entity.computed(Upper, (d) => d.slug.toUpperCase()),
},
invariants: [
Entity.invariant((d) => {
Expand All @@ -143,7 +143,7 @@ test("an invariant sees the declared fields, never a computed one", () => {
);
});

test("computed's function is contextually typed and must return brands", () => {
test("computed's function is contextually typed over the declared fields, but its return needs no brand", () => {
const Upper = z.string().brand("Upper");
Entity("Probe2")(
{ id: OrgId, slug: Slug },
Expand All @@ -158,7 +158,7 @@ test("computed's function is contextually typed and must return brands", () => {
// @ts-expect-error a plain string is not Upper
const bad: { slugUpper: z.infer<typeof Upper> } = { slugUpper: "x" };
void bad;
return "X" as z.infer<typeof Upper>;
return "X";
}),
},
},
Expand Down Expand Up @@ -196,10 +196,10 @@ test("factory generators are functions, and must cover exactly the generated fie
) {}

// `as never` would defeat every assertion below — it is assignable to any
// type, including a function — so these use real branded values.
const id = "0199b1f4-1b1e-7000-8000-000000000000" as z.infer<typeof OrgId>;
const at = "2026-08-06T09:00:00Z" as z.infer<typeof Instant>;
const slug = "s" as z.infer<typeof Slug>;
// type, including a function — so these use real values instead.
const id = "0199b1f4-1b1e-7000-8000-000000000000";
const at = "2026-08-06T09:00:00Z";
const slug = "s";

Org.factory({ id: () => id, createdAt: () => at });

Expand All @@ -224,7 +224,7 @@ test("a computed field is immutable without being declared immutable", () => {
{ id: OrgId, slug: Slug },
{
computed: {
slugUpper: Entity.computed(Upper, (d) => d.slug.toUpperCase() as z.infer<typeof Upper>),
slugUpper: Entity.computed(Upper, (d) => d.slug.toUpperCase()),
},
},
) {}
Expand Down Expand Up @@ -311,7 +311,8 @@ test("producers are castless: from and generators take the schema's input", () =
) {}
void Wrong;

// back-compat: a branded (cast) return still assigns — brand ⊂ input
// Legacy: the one deliberate producer cast left in the repo, kept as the
// back-compat net — do not sweep it.
class Legacy extends Entity("Legacy")(
{ id: StampId, name: Slug },
{
Expand Down
2 changes: 1 addition & 1 deletion packages/entity/src/nesting.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class Customer extends Entity("Customer")(
{ id: CustomerId, name: Name },
{
computed: {
shout: Entity.computed(Upper, (d) => d.name.toUpperCase() as z.infer<typeof Upper>),
shout: Entity.computed(Upper, (d) => d.name.toUpperCase()),
},
},
) {}
Expand Down
Loading