# Types in Fern Definition

> Types describe the data model of your API. Fern has many built-in types and supports custom types, as well as extending and aliasing objects, and unions.

Types describe the data model of your API.

## Built-in types

| Type       | Description                                                                                                         |
| ---------- | ------------------------------------------------------------------------------------------------------------------- |
| `string`   | Basic string type                                                                                                   |
| `integer`  | Integer number type                                                                                                 |
| `long`     | Long integer type                                                                                                   |
| `double`   | Double precision floating point                                                                                     |
| `boolean`  | Boolean true/false                                                                                                  |
| `datetime` | An [RFC 3339, section 5.6 datetime](https://ijmacd.github.io/rfc3339-iso8601/). For example, `2017-07-21T17:32:28Z` |
| `date`     | An RFC 3339, section 5.6 date (YYYY-MM-DD). For example, `2017-07-21`                                               |
| `uuid`     | UUID identifier                                                                                                     |
| `base64`   | Base64 encoded data                                                                                                 |
| `list`     | An ordered collection that allows duplicates, e.g., `list<string>`                                                  |
| `set`      | An unordered collection with unique elements, e.g., `set<string>`                                                   |
| `map`      | Key-value mapping, e.g., `map<string, integer>`                                                                     |
| `optional` | Optional value, e.g., `optional<string>`                                                                            |
| `literal`  | Literal value, e.g., `literal<"Plants">`                                                                            |
| `file`     | File upload type, e.g., [file uploads](/learn/api-definition/fern/endpoints/multipart)                              |
| `unknown`  | Represents arbitrary JSON                                                                                           |

## Custom types

Creating your own types is easy in Fern!

### Objects

The most common custom types are **objects**.

In Fern, you use the `"properties"` key to create an object:

```yaml {3,8}
types:
  Person:
    properties:
      name: string
      address: Address

  Address:
    properties:
      line1: string
      line2: optional<string>
      city: string
      state: string
      zip: string
      country: literal<"USA">
```

These represent JSON objects:

```json
{
  "name": "Alice",
  "address": {
    "line1": "123 Happy Lane",
    "city": "New York",
    "state": "NY",
    "zip": "10001",
    "country": "USA"
  }
}
```

You can also use **extends** to compose objects:

```yaml {6}
types:
  Pet:
    properties:
      name: string
  Dog:
    extends: Pet
    properties:
      breed: string
```

You can extend multiple objects:

```yaml {3-5}
types:
  GoldenRetriever:
    extends:
      - Dog
      - Pet
    properties:
      isGoodBoy: boolean
```

### Aliases

An Alias type is a renaming of an existing type. This is usually done for clarity.

```yaml
types:
  # UserId is an alias of string
  UserId: string

  User:
    properties:
      id: UserId
      name: string
```

### Enums

An enum represents a string with a set of allowed values.

In Fern, you use the `"enum"` key to create an enum:

```yaml {3}
types:
  WeatherReport:
    enum:
      - SUNNY
      - CLOUDY
      - RAINING
      - SNOWING
```

Enum names are restricted to `A-Z`, `a-z`, `0-9`, and `_` to ensure that generated code can compile across all of the languages that Fern can output. If you have an enum that doesn't follow this convention, you can use the `"name"` key to specify a custom name:

```yaml
types:
  Operator:
    enum:
      - name: LESS_THAN # <--- the name that will be used in SDKs
        value: '<' # <--- the value that will be serialized
      - name: GREATER_THAN
        value: '>'
      - name: NOT_EQUAL
        value: '!='
```

### Discriminated unions

Fern supports tagged unions (a.k.a. discriminated unions). Unions are useful for
polymorphism. This is similar to the `oneOf` concept in OpenAPI.

In Fern, you use the `"union"` key to create an union:

```yaml {3-5}
types:
  Animal:
    union:
      dog: Dog
      cat: Cat
  Dog:
    properties:
      likesToWoof: boolean
  Cat:
    properties:
      likesToMeow: boolean
```

In JSON, unions have a **discriminant property** to differentiate between
different members of the union. By default, Fern uses `"type"` as the
discriminant property:

```json
{
  "type": "dog",
  "likesToWoof": true
}
```

You can customize the discriminant property using the "discriminant" key:

```yaml {3}
 types:
   Animal:
     discriminant: animalType
     union:
       dog: Dog
       cat: Cat
   Dog:
     properties:
       likesToWoof: boolean
   Cat:
     properties:
       likesToMeow: boolean
```

This corresponds to a JSON object like this:

```json
{
  "animalType": "dog",
  "likesToWoof": true
}
```

### Undiscriminated unions

Undiscriminated unions are similar to discriminated unions, however you don't
need to define an explicit discriminant property.

```yaml
MyUnion:
  discriminated: false
  union:
    - string
    - integer
```

### Generics

Fern supports shallow generic objects, to minimize code duplication. You can
define a generic for reuse like so:

```yaml
MySpecialMapItem<Key, Value>:
  properties:
    key: Key, 
    value: Value,
    diagnostics: string
```

Now, you can instantiate generic types as a type alias:

```yml
StringIntegerMapItem:
  type: Response<string, number>

StringStringMapItem:
  type: Response<string, string>
```

You can now freely use this type as if it were any other type! Note, generated
code will not use generics. The above example will be generated in typescript as:

```typescript
type StringIntegerMapItem = {
  key: string,
  value: number,
  diagnostics: string
}   
 
type StringStringMapItem = {
  key: string,
  value: string,
  diagnostics: string
}
```

### Documenting types

You can add documentation for types. These docs are passed into the compiler,
and are incredibly useful in the generated outputs (e.g., docstrings in SDKs).

<CodeBlock title="Fern Definition">
  ```yaml
  types:
    Person:
      docs: A person represents a human being
      properties:
        name: string
        age:
          docs: age in years
          type: integer
  ```
</CodeBlock>

<CodeBlock title="Generated TypeScript SDK from Fern Definition">
  ```typescript
  /**
   * A person represents a human being
   */
  interface Person {
    name: string;
    // age in years
    age: number;
  }
  ```
</CodeBlock>

### Validating types

You can add validation constraints to your types (both aliases and references) to ensure data integrity. These validation constraints exist in your API definition and are enforced by the server, but the generated client SDKs don't include validation logic.

<CodeBlock title="Fern Definition">
  ```yaml {8-11, 15-17}
  types:
    Person:
      docs: A person represents a human being
      properties:
        name:
          docs: The person's full name
          type: string
          validation:
            minLength: 2
            maxLength: 100
            pattern: "^[A-Za-z ]+$"
        age:
          docs: Age in years
          type: integer
          validation:
            min: 0
            max: 150
  ```
</CodeBlock>

<AccordionGroup>
  <Accordion title="String validation reference">
    String types support several validation constraints.

    ```yaml {4-6, 11-13, 16-19}
    types:
      Word:
        type: string
        validation:
          minLength: 2
          maxLength: 26
      User:
        properties:
          email:
            type: string
            validation:
              format: email
              maxLength: 254
          username:
            type: string
            validation:
              minLength: 3
              maxLength: 20
              pattern: "^[a-zA-Z0-9_]+$"
    ```

    <ParamField path="minLength" type="integer">
      Minimum number of characters required
    </ParamField>

    <ParamField path="maxLength" type="integer">
      Maximum number of characters allowed
    </ParamField>

    <ParamField path="pattern" type="string">
      Regular expression pattern that the string must match
    </ParamField>

    <ParamField path="format" type="string">
      String format specification (e.g., "email", "uri", "date-time")
    </ParamField>
  </Accordion>

  <Accordion title="Number validation reference">
    Number types (including `integer`, `long`, and `double`) support several validation constraints.

    ```yaml {4-6, 12-15, 18-20}
    types:
      Age:
        type: integer
        validation:
          min: 0
          max: 150
      Product:
        properties:
          name: string
          price:
            type: double
            validation:
              min: 0
              exclusiveMin: true
              multipleOf: 0.01
          quantity:
            type: integer
            validation:
              min: 1
              max: 1000
    ```

    <ParamField path="min" type="number">
      Minimum value (inclusive by default)
    </ParamField>

    <ParamField path="max" type="number">
      Maximum value (inclusive by default)
    </ParamField>

    <ParamField path="exclusiveMin" type="boolean">
      When true, the minimum value is exclusive (value must be greater than min)
    </ParamField>

    <ParamField path="exclusiveMax" type="boolean">
      When true, the maximum value is exclusive (value must be less than max)
    </ParamField>

    <ParamField path="multipleOf" type="number">
      Value must be a multiple of this number
    </ParamField>
  </Accordion>
</AccordionGroup>