Type combinators

Here's some information about some special types combining other types.

types.union: Either of multiple types

You can use types.union(int, str) to indicate that a field depends on either an integer or a string.

Note

Unions are ordered. This means that types.union(int, float) != types.union(float, int).

This is relevant when two or more types in the union can accept the same native type, with differing checks or casts. In the case of int and float, the integer 5 will remain the integer 5 when casting to types.union(int, float), but will be casted to the float 5.0 when casted to types.union(float, int). (Of course, a float such as 4.0 will remain a float in both cases, since it isn't accepted by int).

Optional and smart types

For fields that can be set to none to indicate absence, use types.option(typ). This is the same as types.union(none, typ).

For fields with a smart default indicated by auto, use types.smart(typ). This is the same as types.union(auto, typ).

You can also combine both: types.option(e.types.smart(typ)) is the same as types.union(none, auto, typ).

Folding in unions

Folding is preserved in unions unless it's ambiguous. For example, it is preserved for types.union(int, stroke, array): two arrays of this type are joined, a length and a color are cast to stroke and combined into a single length + color stroke, and integers have no folding and stay that way (the latest integer has priority).

However, if you have types.union(types.array(int), types.array(float)), folding is disabled (the latest array overrides the previous) as it is not straightforward to tell to which type an array could belong, so we avoid creating an invalid instance of this type (which could happen if we joined an int array with a float array).

types.exact: Disable casting for a type

You can use types.exact(typ) to ensure there is no casting involved for this type. For example, types.exact(float) ensures integers won't cast to floats (they are normally accepted). Also, types.exact(stroke) ensures only stroke(5pt) can be passed to a field with that type, not 5pt itself. Finally, types.exact(my-custom-type), where my-custom-type has custom casts from existing types, disables those casts, allowing only an instance of my-custom-type itself to be used for a field with that type.

types.array: Array of a type

You can use types.array(typ) to accept arrays of elements of the same type.

types.dict: Dictionary with values of a type

You can use types.dict(typ) to accept dictionaries with values of the same type. (Note that dictionary keys are all strings.)

For example, (a: 5, b: 6) is a valid dict(int), but not a valid dict(str).