Mocking in TypeScript with `factoree`
Tags: typescript, javascript, testing
Published: 2021-04-06 17:35:17

---
title: Mocking in TypeScript with `factoree`
published: true
date: 2021-03-02 00:00:00 UTC
tags: typescript, javascript, testing
canonical_url: https://gal.hagever.com/posts/mocking-in-typescript-with-factoree/
---

A couple of days ago I had a fantastic experience. Two ambitious developers asked me to review an open source project they are working on in a short video chat. I was flattered and happily accepted the offer.

We found ourselves talking about mocks in TypeScript. Since I started using TypeScript, I adopted a practice where I try to push as much as I can to the type system and use tools like [`io-ts`](https://github.com/gcanti/io-ts) to hook just enough runtime validations to ensure I can trust it.

A couple of months ago I needed to mock something in one of our tests. We have a pretty big config, generated from a confirmation system, and I needed to use a property from it in my test.

The first idea was to do something like `setAppConfig({ myKey: value } as any)`. This worked well but it stinks from the `any`, which also have a very big drawback: what if the test is implicitly using a property I did not set?

Enter [`factoree`](https://github.com/Schniz/factoree). A simple factory generator function which will immediately throw an error when accessing a missing property. So, the previous example would be something like:

```typescript
import { factory } from "factoree";

const createAppConfig = factory<AppConfig>();

setAppConfig(createAppConfig({ myKey: value }));
```

Can you see that we no longer have `as any`? Instead of skipping the type system, we generate an object which will throw an error if we accessed a missing key. Instead of playing pretend — we specify rules for the computer to enforce at runtime:

```typescript
import { factory } from "factoree";
const createAppConfig = factory<AppConfig>();

const config = createAppConfig({ myKey: "hello" });
config.myKey; // => 'hello'
config.otherKey; // => Error: Can't access key 'otherKey' in object { myKey: 'hello' }
```

## Why does it matter?[<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#why-does-it-matter)

Imagine the following code under test:

```typescript
export type User = {
  firstName: string;
  lastName: string;

  // more data
  website: string;
};

export function printName(user: User): string {
  return `${user.firstName} ${user.lastName}`;
}
```

And when we test it, we can use `as unknown as User` to provide only the things that are in use in our function:

```typescript
test(`prints the name`, () => {
  const userDetails = ({
    firstName: "Gal",
    lastName: "Schlezinger",
  } as unknown) as User;
  const result = printName(userDetails);
});
```

Now, the product manager asked us to add another feature: allow a user’s name to be written in reverse. So, our code changes into:

```typescript
export type User = {
  firstName: string;
  lastName: string;
  prefersReversedName: boolean;

  // more data
  website: string;
};

export function printName(user: User): string {
  if (user.prefersReversedName) {
    return `${user.lastName} ${user.firstName}`;
  }

  return `${user.firstName} ${user.lastName}`;
}
```

After the code change, tests should still pass. This is a problem because we access a property (`prefersReversedName`) which should be a non-null `boolean`, but we don’t pass value into it, which is `undefined`. This creates a blind spot in our test. When using factoree, this would not happen: if you forget to define a property, factoree will throw an error — ensuring you can trust your types.

* * *

This tiny library helped us make more maintainable code with easier assertions and better tests. No more `undefined` errors in tests if types have changed. Let the computer do the thinking for us.

[Try it](https://github.com/Schniz/factoree), and let me know how that worked for you!