Type system features

Definition
Language features regarding the types of data

Features

Static Typing (C, C++, Java, C#, Rust, Go, Haskell, Scala, TypeScript, Swift) Variables have types known at compile time, enabling type checking and optimizations before execution.

Dynamic Typing (Python, JavaScript, Ruby, PHP, Lisp, Perl) Variables can hold values of any type and type checking is done at runtime.

Type Inference (Haskell, Scala, Rust, Kotlin, Swift, F#, OCaml) The compiler automatically deduces the type of a variable or expression.

Duck Typing (Python, Ruby, JavaScript, PHP) Type compatibility is determined by behavior (methods/properties) rather than inheritance.

Nominal Typing (Java, C++, C#) Types are considered compatible based on explicit declarations and names.

Structural Typing (TypeScript, Go, Scala, OCaml) Type compatibility is determined by the structure (fields/methods) of types rather than names.

Union Types (TypeScript, Flow, Haskell, Elm, F#) A value may be one of several explicitly declared types.

Nullable Types (Kotlin, TypeScript, Swift, C#) Types that explicitly allow null or undefined values to improve safety.

Optional Types (Swift, Rust, Haskell, Scala, F#) Variables can either contain a value or be empty (None, Nil, null).

Generics / Parametric Polymorphism (Java, C#, C++, Rust, TypeScript, Scala, Haskell) Allows code to be written generically for any data type while preserving type safety.

Type Constraints (Scala, Haskell, Rust, C#) Restrict generic types to certain conditions or interfaces.

Dependent Types (Idris, Agda, Coq, F*) Types that depend on values, enabling very precise type constraints at compile time.

Refinement Types (LiquidHaskell, F*, Idris) Types that are enriched with logical predicates to enforce invariants.

Phantom Types (Haskell, Scala, Rust) Compile-time-only types used to enforce constraints without affecting runtime behavior.