Special types

There are some special types which don't correspond precisely to a single native or custom type, but have special behavior.

types.any: Accepting any values

You can use types.any to ensure a field can receive any value (disables typechecking, folding, and any kind of special behavior).

types.never: Accepts no values

This exists more for completeness, but this is a type with no input types, so it is impossible to cast to it.

types.literal: Accepting only a single value of a type

You can use types.literal("abc") to only accept values equal to "abc". As a shorthand, you can write just "abc" as the type for the field (unless it is a dictionary or function, as it'd then be ambiguous with other types).

To accept more than one literal, you can use types.union, e.g. types.union("abc", "def") for either "abc" or "def".

Note that casting is preserved: types.literal(5.0) will accept either the integer 5 or the float 5.0. To accept just the float 5.0, you can use types.exact(types.literal(5.0)), for example.

types.custom-type: Accept custom types themselves

To accept any custom type as a value, you can use types.custom-type. However, note that, due to ambiguity when passing functions, the user will have to pass e.data(the-custom-type-constructor) instead of just the constructor itself for the cast to work / for the field to typecheck.

The same goes for literals: to receive one of multiple custom types, you'll have to use union(literal(e.data(type1)), literal(e.data(type2))). Note that you have to use literal to disambiguate.

For native types, you can just use type as the type, and they will be accepted without any special ceremony by the user (they can pass int to a type field and it works). However, note that writing literal(int) explicitly, for example, is still required to only accept certain native types' constructors.

Native and custom elements are not currently supported on their own, although you may have some success in accepting function.