Guide
Placeholder

Defining Placeholders

When defining dependent properties or variables, you cannot reference other properties or variables within .define, so sometimes you may want to set placeholder values. In such cases, you can use later to define only the type, setting the actual value later.

import { factory, later } from "@factory-js/factory";
 
const userFactory = factory
  .define({
    props: {
      firstName: () => "John",
      lastName: () => "Doe",
      // Define only the type to allow TypeScript to infer it, and set the actual value later
      fullName: later<string>(),
    },
    vars: {},
  })
  .props({
    // Set the value of `fullName` here
    fullName: async ({ props }) =>
      `${await props.firstName} ${await props.lastName}`,
  });

If you use this factory without setting the value of this property later, later will throw an exception. This way, you can catch mistakes if you forget to set the value.

import { factory, later } from "@factory-js/factory";
 
const userFactory = factory.define({
  props: {
    firstName: () => "John",
    lastName: () => "Doe",
    fullName: later<string>(),
  },
  vars: {},
});
 
userFactory.build(); // ❌ Throws an exception because `fullName` is not set

Defining Properties Without Default Values

Another use of later is to define properties without default values. In the example below, the type property is defined with later.

factories/item-factory.ts
import { factory, later } from "@factory-js/factory";
 
export const itemFactory = factory.define({
  props: {
    type: later<"book" | "food">(),
    price: () => 0,
  },
  vars: {},
});

By defining properties this way, you ensure that values must be set in advance using .props when creating objects with the factory. Otherwise, an exception will be thrown.

import { expect, it, describe } from "vitest";
import { itemFactory } from "../factories/item-factory";
import { isFood } from "./is-food";
 
describe("when the type is food", () => {
  it("returns true", async () => {
    // ✅ No exception is thrown because `type` is set
    const item = await itemFactory.props({ type: () => "food" }).build();
    expect(isFood(item)).toBe(true);
  });
});
 
describe("when the type is book", () => {
  it("returns false", async () => {
    // ❌ Throws an exception because `type` is not set
    const item = await itemFactory.build();
    expect(isFood(item)).toBe(false);
  });
});