How Typescript Generics Work
Tags: typescript, webdev, tutorial
Published: 2021-01-19 06:31:00

> The following article is a free sample from [EasyWebDev](https://easywebdev.substack.com/) mailing list. [Subscribe](https://easywebdev.substack.com/) to get simple web development guides, tutorials, and explanations.

If you've been using Typescript, there is a good chance that you've come across [Generics](https://www.typescriptlang.org/docs/handbook/generics.html). Generics are a handy Typescript feature that allows you to declare variable types for your interfaces, types, and declarations.

```ts
interface GenericInterface<T> {
    prop: T;
}
```

`T` is a Generic that allows the _consumer_ to specify the type for our property `prop`. This is handy in situations where all the possible types are not known ahead of time or where there are a wide variety of types that we don't need to constrain on the interface level.

## Using Generics

Using generics in your application code is conceptually very similar to passing arguments to to your functions. However, instead of passing run time values, we are passing Typescript type definitions.

```ts
const myObject: GenericInterface<string> = {
    prop: 'string'
}
```

Generics make our code more flexible but they still also guarantee type safety.

```ts
const myObject: GenericInterface<string> = {
    prop: 1, // Error! string is passed to the generic, but a number is specified.
}
```

## Non-Trivial Types

### Complex Types

The values passed to a Generic do not need to be simple types. Any valid Typescript expression is allowed. The important take-away is that the concrete value must adhere to the Generics' type, whatever it is.

```ts
const unionObject: GenericInterface<string | number> = {
    prop: 1; // this can be either a string or a number
}

const typeofObject: GenericInterface<typeof window.document> = {
    prop: window.document; // this can only be an object that matches the type from window.document
}
```

### Multiple Generics

There is no limit to the number of generics that you can define for a given interface, type, or declaration.

```ts
interface GenericInterface<A, B, B> {
    prop: A;
    next: B;
    another: C;
}
```
## Default Types

When a generic is defined, the caller always has to specify a type for the generic. To get around this requirement, Generics can be assigned default types. When a default type is used and a type has not been specified, Typescript will use the default Generic type.


```ts
interface GenericInterface<A = string> {
    prop: A;
}

const myObject: GenericInterface = {
    prop: 'string'
}
```

Default types allow you to do some very complex and interesting inference. Here is a silly example:

```ts
interface GenericInterface<A extends { prop: string | number }, B = A['foo']> {
    a: A;
    b: B
}

const obj: GenericInterface<{ prop: string }> = {
    a: {
        prop: 'string',
    },
    b: 1 // Error! b MUST match the type from a.prop.
}
```

## Constraining Generics

By default there are no constraints on the types that can be passed to a Generic. Sometimes, however, we want to constrain a Generic's type. One way we can do this is aliasing the constraint to a new type. This applies a localized constraint and does not globally constraint the Generic's type.

```ts
type Constrained = GenericInterface<string>;
function myfunction(arg: Constrained) {

}
```

Another way to constraing Generics is on the Generic's definition itself. This constraint will apply to _any_ usage of the Generic, so all callers will need to adhere to the constraint when using `extends` directly in the Generic's definition.


```ts
interface GenericInterface<T extends string> {
    prop: T
}
```

## Naming Generics

This is a [somewhat controversial](https://twitter.com/kentcdodds/status/1348016701632221184) topic, but there is a long-standing convention to use single letter names for your Generics. I would encourage you to use whatever approach works best for your team and application.


Happy coding!


**Enjoy this article? [Subscribe to EasyWebDev!](https://easywebdev.substack.com/)**