CLS has a static type system that operates entirely at compile time. The type checker, invoked withDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/elfrask/cls/llms.txt
Use this file to discover all available pages before exploring further.
clx check, validates your program before it runs — catching type mismatches, invalid assignments, and unresolved names. The runtime tree-walking interpreter does not use type information; types have no effect on execution, only on static analysis. This gives you the safety of static typing with the flexibility of a dynamic interpreter during development.
The type system is purely compile-time. Running
clx run skips type checking. Use clx check explicitly to validate your types before shipping.Primitive Types
CLS has eight built-in primitive types. Both long-form and short-form aliases are accepted in type annotations.| Type | Aliases | Description |
|---|---|---|
Int | int, i32, i64, Integer | 64-bit signed integer |
Float | float, f32, f64 | 64-bit floating-point number |
String | str | UTF-8 character string |
Bool | bool, Boolean | Boolean value (true or false) |
Char | char, Character | A single Unicode character |
Any | any | Dynamic type — assignable to and from everything |
Null | — | The null value |
Void | void | No value; used for procedures with no return |
Arrays
Arrays are ordered, homogeneous, mutable collections. The type is written asElementType[], or equivalently Array<ElementType>. The type checker infers Array<T> from the type of the first element in a literal.
Tuples
Tuples are heterogeneous, immutable, fixed-length sequences. The type is written as(T1, T2, ...) listing each slot’s type. Positional access with a literal index yields the exact type of that slot; access with a dynamic (variable) index yields the union of all slot types.
Records
Records are typed key-value dictionaries, declared asRecord<KeyType, ValueType>. The type checker infers Record<String, T> from an object literal, where T is the common value type.
Union Types
A union typeA | B | C accepts values whose type matches any of its members. Unions of string, number, or boolean literals are particularly useful for constraining values to a finite set — similar to enums in other languages.
Literal Types
A literal type represents a single, exact value.const declarations infer literal types; var and let declarations infer the base type.
"CLS" is assignable to String), but the reverse is not true — String is not assignable to "CLS" without an exact match. This makes const ideal for building discriminated union members.
Type Aliases
Thealias keyword creates a named type synonym. Aliases only exist at compile time and have no runtime cost.
Interfaces
Interfaces declare the shape of an object: its fields (with types) and its methods (with parameter and return types). They are purely compile-time constructs and support generic type parameters with optional defaults.name: Type and methods as name(params): ReturnType. Comma-separated members are terminated by };.
Type Extraction
You can extract the type of a named field or positional slot from an interface or tuple using the subscript syntaxT["field"] or T[index]. Generic arguments are substituted before extraction.
Generics
Functions, classes, and interfaces can all be parameterized with type variables written inside<> after the name.
- Generic functions
- Generic classes
- Generic interfaces
The type checker infers type arguments from the call-site values, so you rarely need to supply them explicitly.
Phantom Types
A phantom type parameter!T marks a generic parameter that does not participate in the types of any members. It is not substituted and not unified during type checking. Phantom parameters are used to attach additional type-level identity to a structure without affecting its runtime shape.
Phantom parameters are an advanced feature for compile-time type tagging. They have no runtime representation and do not affect how values are stored or accessed by the interpreter.
Assignment Rules
The type checker uses these rules to decide when an assignmentx: A = expr (where expr has type B) is valid:
| Rule | Description |
|---|---|
Any compatibility | Any is assignable to every type, and every type is assignable to Any |
| Identity | Identical types are always assignable |
| Numeric widening | Int is assignable to Float |
| Literal → base | A literal type (e.g. "red") is assignable to its base type (String) |
| Literal → literal | Only if the literal values match exactly |
| Union membership | A union type A | B is assignable to T if at least one member is assignable to T |
| Tuple positional | Tuples are compared position-by-position |