Skip to main content

FormNodeValue

FormNodeValue<typeof node> extracts the committed value type of any form(), group(), array(), or field() instance. Use it to type saved drafts, service parameters, or other values that should follow a node's inferred model.

import type { FormNodeValue } from '@ngblocks/form-nodes';

type MyFormValue = FormNodeValue<typeof myForm>;

🌳 Infer form and child values

import { array, field, form, type FormNodeValue } from '@ngblocks/form-nodes';

const profile = form({
name: field('Marco'),
country: field.strict<string>('Switzerland'),
address: { city: field('Zurich') },
contacts: array({
email: field(''),
}, {
initialValue: [{ email: 'marco@example.com' }],
}),
});

type ProfileValue = FormNodeValue<typeof profile>;
// {
// name: string;
// country: string;
// address: { city: string };
// contacts: { email: string }[];
// }

type NameValue = FormNodeValue<typeof profile.name>; // string
type AddressValue = FormNodeValue<typeof profile.address>; // { city: string }
type ContactsValue = FormNodeValue<typeof profile.contacts>; // { email: string }[]

const name: NameValue = 'Ada';
const address: AddressValue = { city: 'Bern' };
const contacts: ContactsValue = [{ email: 'marco@example.com' }];

const draft: ProfileValue = {
name,
country: 'Switzerland',
address,
contacts,
};

profile.set(draft);

The same helper works for the complete form and each selected child. It preserves each node's value type recursively:

  • Fields retain their inferred or declared nullability; field.nullable() explicitly includes null.
  • Explicit undefined, literal unions, and application-specific object types are preserved.
  • Groups and nested forms produce nested objects.
  • Dynamic arrays produce arrays of their item values. An array-valued field retains its own field type, including nullability of the complete array.
  • Nodes created with createFormPrimitives() preserve their configured nullability defaults and any explicit field overrides.

📐 Signature and scope

type FormNodeValue<TNode extends AnyNode> = ReturnType<TNode>;

Pass the type of an existing node instance. Standalone nodes, nested nodes, and array items are all supported. Definition objects and ordinary functions are not node instances. When an array item may be missing, narrow out undefined or use NonNullable on its type first.

The result is equivalent to ReturnType<typeof node> and describes what calling node() returns. It also works when children are named value, api, or nodeType, since those names do not change the node's call signature.

The helper follows the static declaration. Adding a child with add() later does not widen the original form or group type; use the returned child for its exact inferred type.

This is a type-only export. It does not read the node, create a subscription, validate a value, or change runtime behavior.

TypeInputPurpose
FormNodeValue<typeof node>Any node instance typeExtract its committed value type.
FormValue<TNodes>A map of child-node typesMap each child node to its value type.
FormValueContract<Model>An existing object value modelCheck an inferred form or group with satisfies.

Use FormNodeValue when the node declaration defines your model. Use FormValueContract when an existing domain model should constrain the form declaration.