liveBook · Manning

Type system

As explained in F# in Action: A Revised Edition of Get Programming with F#

A type system is a set of rules that assigns types to program expressions and constrains how values and operations may be combined.

A type system assigns shapes to values and checks how those values can be combined. In F#, it supports concise, type-safe code: the compiler can infer many types, so explicit annotations and class-heavy designs are often unnecessary. The result is a practical balance between lightweight syntax and compiler-backed guidance. section 1.1 section 2.1.2

Its main job is domain modeling. Start with primitive and .NET types, then compose them into types such as customers and orders. Records, tuples, anonymous records, lists, and discriminated unions provide different ways to express the data relationships a real system needs. section 5.0 section 8.0

Choose a representation that states the relationship clearly:

  • Use a list when a field can hold any number of values of one type, such as a customer's addresses. section 8.4.3
  • Use separate record fields when values have distinct roles, such as billing and postal addresses. section 8.4.3
  • Combine records and unions when a model needs both named fields and alternative cases; use single-case discriminated unions to distinguish otherwise similar primitive fields. section 8.4.3
type CustomerWithAddresses =
    {
        Name : string
        Addresses : Address list
    }

A list models repeated addresses as one `Address list` field; the number of entries does not change the record's type structure. section 8.4.3

type CustomerWithAddresses =
    {
        Name : string
        BillingAddress : Address
        PostalAddress : Address
    }

Two explicit fields model two required address roles, making billing and postal addresses distinct in the data shape. section 8.4.3

Treat the compiler as an active design partner. As types are modeled and functions map one shape to another, compiler feedback helps expose mismatches before the application is run. This supports iterative exploration: model a domain with in-memory data, test ideas cheaply, and refine the shared vocabulary with domain experts. section 1.5.3 section 1.5.1

From manual composition to typed composition

A small pipeline can filter even numbers and then square them. Type inference keeps the F# version brief while static typing and the compiler still check the pieces being composed. This makes small, focused functions easier to assemble into larger behavior with confidence. section 2.1.2

The type system is useful beyond server applications. F# runs on .NET, interoperates with C#, and can compile to JavaScript through Fable, allowing statically typed F# to work alongside ecosystems such as ASP.NET Core, React, and existing .NET libraries. section 1.1 section 1.3

How F# in Action: A Revised Edition of Get Programming with F# covers it

How deep it goes
Introduces composition from primitives through records, tuples, lists, and discriminated unions, while deferring fuller treatment of several techniques.
Examples
Contrasts list-held addresses with billing and postal record fields, and composes filtering with squaring functions.
What it assumes
Starts with primitive and built-in .NET types before introducing ways to compose custom domain types.
What you can do after
Evaluate/understand how to model domain relationships and use compiler feedback to refine type-safe code.
How it connects
Connects type inference, compiler guidance, records, tuples, lists, discriminated unions, pattern matching, and function composition.

Also explained in

Compare how 6 books explain type system →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of F# in Action: A Revised Edition of Get Programming with F#. The section links point to the parts of the book it draws on.