Type Constraints In TypeScript
Tags: typescript, javascript, functional
Published: 2020-11-12 16:14:04

---
title: Type Constraints In TypeScript
published: true
description: Narrow the set of values that a generic type could be
tags: typescript, javascript, functional
cover_image: https://images.unsplash.com/photo-1455654891086-6849e1aa58a6
---

> Photo credit: https://unsplash.com/photos/ar2dUoleWYA

---

Suppose you're a back end API developer and you need a way to **guarantee at compile time** that you're only sending json-serializeable data out of your API. 

You have a `send` function that takes some data and sends it to a API consumer.

```typescript
const send = <T>(data: T): Promise<null> => {
  // magic...
  // or more realistically
  // calls express' res.json() method!
}
```

And you're trying to prevent a dev from trying to send the following out of your api:

```typescript
send({
  makesNoSense: () => { console.log('woops!') },
  myDate: new Date(), 
})
```

The above would be stringified (i.e. serialized) under the hood into `{ myDate: 'iso-date-string' }`. Functions aren't part of the JSON spec and thus would be removed entirely. And `Date`s are automatically cast to strings which is not a very efficient way of sending timestamps down the network (hint: you want unix timestamps in the form of an integer). 

Woops! Looks like a dev forgot to call a function and also forgot to call `Date.getTime` 😭

So how do we prevent this sort of thing?

## Type Constraints To The Rescue

A type constraint is a "rule" that narrows down the possibilities of what a generic type could be. 

For example, in the the `send` definition above, we declared a type variable `T` that is not constrained at all. Which is why we were able to call `send` with values that aren't JSON serializeable. 

```typescript
// This compiles ... API would send `{}`
send(new Set([1,2,3]))
```

We can thus narrow the possibilities of the generic type `T` to allow allow JSON values as follow:

```typescript
const send = <T extends JSONValues>(data: T): Promise<null> => {
  // ...
}
```

The only difference is that now we've appended `extends JSONValues` to the type variable declaration for `T`. 

In plain english `T extends JSONValues` translates to, "`T` is a generic type that must conform to the definition of `JSONValues`".

What's `JSONValues`?

It's defined as this:

```typescript
type JSONValues
    = number
    | string
    | null
    | boolean
    | { [k: string ]: JSONValues }
    | JSONValues[]
```

... Yup, this is the **entire JSON specification** in 7 lines of code! 🤯

Now, if I call `send(new Set([1,2,3]))` I will get a type error. Whaaaat?!?!

Now you can guarantee at compile-time that you will only send valid data to your JSON API consumers :)

[Live demo](https://www.typescriptlang.org/play?#code/FAFwngDgpgBAUgZQPIDkBqBDANgVygZ2BmJgF4YA7HAWwCMoAnIkgHxnxAYEsKBzZ4mypYsAmG1oB7SVigYKYtgG8YAbQDWALnacevGAF1tiVJlwEYAX0Xxk6bHnyqDwYAGNJFDuygUAJmQwADwAKjBQAB4gvn74tqYOBAB8ABQAbtjaIQCU2gAKDJLUXPhQQcJYSWRVSmImKAB0HNx8XABmYOnY2TAA9L0+-jAgkjBthRQg4UM4+HrhERAMBPgA5DDL+A0AVvieKT3UUCAAFpJ+riQbxzgMFDAFRSVQDZsyaVApFdnA1u6e3gyWAAjIFSv4UsCAEwAZh+Hi8UyBULBMRSqjEKgoGCO2lWUloqwANDAMLwoNpoTCSSUAMLSLDaTh4SxEsSrSQnGAnKBgYY85arYAGH7AfowADu0ggcwIAEJ+SUYCUKKskdguAF6gqACKamBgSQ4GBHeTDUZubBYGANckgEJcI7mwYBM08aLkhgwIF4AD8-0R3uwqIhFCgEpgOow0QOoqAA)

### Conclusion

Type constraints are a very powerful way to supercharge your typescript codebases.

For each generic type variable that you'd like to constrain, you would append the `extends SomeTypeName` to the definition. Example:

```typescript
const myFn = <T extends JsonValues, U extends FinancialData>() => {...}
```

Hope that helps!

---

#### Shameless Plug

Liked this post?

I stream functional programming, TypeScript and Elm development every Tuesday at 10am on Twitch!

https://www.twitch.tv/vimboycolor