# There is no such thing as a generic

I want to start this course with an idea that will change the way you think about generics.

There is no such thing as a 'generic'.

There are **generic types**, **generic functions**, and **generic classes**.

There are **type arguments** and **type parameters**.

You cannot 'pass' a generic, 'declare' it, or 'infer' it.

In other words, 'generic' is not a noun, it's an adjective.

## "A generic"

People think of 'a generic' as _something_ in TypeScript.

You might look at the code below and say 'we're passing a generic to useState'.

```ts twoslash
import { useState } from "react";

useState<string>();
//       ^^^^^^ Generic
```

You might also say 'we're passing two generics to `Record`':

```ts twoslash
type NumberRecord = Record<string, number>;
//                         ^^^^^^  ^^^^^^ Generics
```

How about '`Maybe` has two generics'?

```ts twoslash
type Maybe<T> = T | null | undefined;
//         ^ Generic
```

People look at the angle bracket syntax and think 'that's a generic'. But because generics can appear on functions, function calls, types, and type declarations, it's not clear what 'a generic' even is.

That's why it's such a hard concept for folks to grasp - the word is too overloaded.

So, what terms should we use instead?

## Type Arguments

How would we describe this code if we couldn't use the word 'generic'?

```ts twoslash
import { useState } from "react";

useState<string>();
```

We're not passing a 'generic' to `useState`. We are passing it a **type argument**. And the **type argument** we're passing is `string`.

How about `Record`?

```ts twoslash
type NumberRecord = Record<string, number>;
```

We're passing two **type arguments** to `Record`. The first **type argument** is `string`, and the second **type argument** is `number`.

So - a type argument works just like a function argument. We can pass it to a function, class, or type.

But not all types, functions, and classes can receive type arguments:

```ts twoslash
// @errors: 2315 2558
type Example = PropertyKey<string>;

encodeURIComponent<string>();

new Event<string>();
```

So how do we know which ones can receive them?

You have generic types:

```ts twoslash
// Generic Type
type Maybe<T> = T | undefined | null;
//         ^ Type Parameter

type MaybeString = Maybe<string>;
//                       ^^^^^^ Type Argument
```

And generic functions.

```ts twoslash
// Generic Function
const uniqueArray = <T>(array: T[]) => {
  //                 ^ Type Parameter

  return Array.from(new Set(array));
};

const uniqueStrings = uniqueArray<string>(["a", "b", "a"]);
//                                ^^^^^^ Type Argument
```

## Type Parameters

Let's look at our `Maybe<T>` from earlier.

```ts twoslash
type Maybe<T> = T | null | undefined;
```

Here, `Maybe` is declaring a **type parameter**. The **type parameter** is `T`.

This means that `Maybe` MUST be passed a type argument. If we don't pass it a type argument, we get an error:

```ts twoslash
// @errors: 2314
type Maybe<T> = T | null | undefined;

// ---cut---

type Example = Maybe;
```

So, a **type parameter** is like a function parameter. It declares that you can pass a type argument to the type, function, or class.

## Generic Types

Let's bring the phrase 'generic' back into our vocabulary and give it a proper definition.

> **generic** - _adj_: a type, function, or class that declares one or more type parameters.

So, `Maybe` is a generic type because it declares a type parameter.

And `PropertyKey`, which we saw earlier, is NOT generic. Even the error says so.

```ts twoslash
// @errors: 2315
type Example = PropertyKey<string>;
```

So, generic types are simply types that declare type parameters.

## Generic Functions and Generic Classes

Functions and classes can also declare type parameters. When they do, they become generic functions and generic classes and can receive type arguments.

```ts twoslash
const myFunc = <T>() => {
  //            ^ Type Parameter
};

myFunc<string>();
//     ^^^^^^ Type Argument
```

```ts twoslash
class MyClass<T> {
  //          ^ Type Parameter
  // implementation...
}

new MyClass<string>();
//          ^^^^^^ Type Argument
```

This can be used in all sorts of ways. By far the most popular is to provide type information to third-party libraries. In the example below, how would `useState` know what type it's supposed to be returning?

```ts twoslash
import { useState } from "react";

const [message, setMessage] = useState(); // message is undefined
```

It can't - so we have to pass a type argument to it.

```ts twoslash
import { useState } from "react";

// message is string | undefined
const [message, setMessage] = useState<string>();
```

## Why This Matters

The term "generic" has become far too overloaded. When we mix up type arguments and parameters with generic functions and types, it's hard to understand what's going on.

For me, learning generics really clicked when I understood that these concepts are separate:

| Concept          | Example                                            |
| ---------------- | -------------------------------------------------- |
| Generic Type     | `type MyType<T> = T`                               |
| Generic Function | `const myFunc = <T>() => {}`                       |
| Type Parameter   | `T` in `MyType<T>` or `myFunc<T>`                  |
| Type Argument    | `string` in `MyType<string>` or `myFunc<string>()` |

In this course, I'll be taking you through each of these ideas in turn. We'll start with how to use generic types to DRY up your type code. Then, we'll head to generic functions and classes.

By the end of this course, I guarantee you'll understand generics at a much deeper level. You'll know when to use them, and what to use them for.

Want to get the next lesson now? Click the link below.
