npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

ts-factory

v2.0.1

Published

A way to build factories for TypeScript objects

Downloads

348

Readme

ts-factory

A way to build factories for TypeScript objects

Travis CI npm GitHub license

Installation

$ npm install ts-factory
$ yarn add ts-factory

buildFactory

buildFactory<T extends object>(defaultObject: T): (overrides?: Partial<T>) => T

buildFactory takes a type parameter and a default object of that type. It returns a function that takes an optional partial object of field overrides.

Example

Consider the following types:

interface Author {
  id?: number;
  name: string;
  email: string;
}

interface Comment {
  id?: number;
  author: Author;
  text: string;
}

interface BlogPost {
  id?: number;
  author: Author;
  title: string;
  body: string;
  comments: Comment[];
}

We can make a factory for Author by calling buildFactory with a default object. Note that optional fields may be omitted.

import { buildFactory } from "ts-factory";

export const buildAuthor = buildFactory<Author>({
  name: "Grant Hutchins",
  email: "[email protected]"
});

We can now use the buildAuthor() function to construct Author instances.

buildAuthor();
// returns {
//   name: "Grant Hutchins",
//   email: "[email protected]"
// }

buildAuthor({});
// returns {
//   name: "Grant Hutchins",
//   email: "[email protected]"
// }

buildAuthor({name: "Mr. Hutchins"});
// returns {
//   name: "Mr. Hutchins",
//   email: "[email protected]"
// }

buildAuthor({id: 1});
// returns {
//   id: 1,
//   name: "Grant Hutchins",
//   email: "[email protected]"
// }

We can now use buildAuthor to make it easier to build a factory for Comment.

import { buildFactory } from "ts-factory";

export const buildComment = buildFactory<Comment>({
  author: buildAuthor(),
  text: "myText"
});

Now we can easily build a Comment, knowing that its Author will also be valid.

buildComment();
// returns {
//   author: {
//     name: "Grant Hutchins",
//     email: "[email protected]"
//   },
//   text: "myText"
// }

buildComment({});
// returns {
//   author: {
//     name: "Grant Hutchins",
//     email: "[email protected]"
//   },
//   text: "myText"
// }

buildComment({id: 1});
// returns {
//   id: 1,
//   author: {
//     name: "Grant Hutchins",
//     email: "[email protected]"
//   },
//   text: "myText"
// }

const anotherAuthor = buildAuthor({
  id: 2,
  name: "Another Author",
  email: "[email protected]",
});

buildComment({author: anotherAuthor});
// returns {
//   author: {
//     id: 2,
//     name: "Another Author",
//     email: "[email protected]"
//   },
//   text: "myText"
// }

We can use buildComment to make it easier to build the default array of comments in buildBlogPost.

export const buildBlogPost = buildFactory<BlogPost>({
  author: buildAuthor(),
  title: "myTitle",
  body: "myBody",
  comments: [buildComment()]
});

Now you can confidently build a BlogPost with as much or as little data as you want.

buildBlogPost();
// returns {
//   author: {
//     name: "Grant Hutchins",
//     email: "[email protected]"
//   },
//   title: "myTitle",
//   body: "myBody",
//   comments: [
//     {
//       author: {
//         name: "Grant Hutchins",
//         email: "[email protected]",
//         text: "myText"
//       }
//     }
//   ]
// }

buildBlogPost({
  id: 3, 
  comments: []
});
// returns {
//   id: 3,
//   author: {
//     name: "Grant Hutchins",
//     email: "[email protected]"
//   },
//   title: "myTitle",
//   body: "myBody",
//   comments: []
// }

buildBlogPost({
  id: 3, 
  author: buildAuthor({id: 4}),
  comments: [
    buildComment({
      id: 5,
      author: buildAuthor({
        id: 6
      })
    }), 
    buildComment({
      author: buildAuthor({
        id: 7
      })
    }), 
  ]
});
// returns {
//   id: 3,
//   author: {
//     id: 4,
//     name: "Grant Hutchins",
//     email: "[email protected]"
//   },
//   title: "myTitle",
//   body: "myBody",
//   comments: [
//     {
//       id: 5,
//       author: {
//         id: 6,
//         name: "Grant Hutchins",
//         email: "[email protected]",
//       },
//       text: "myText"
//     },
//     {
//       author: {
//         id: 7,
//         name: "Grant Hutchins",
//         email: "[email protected]",
//       },
//       text: "myText"
//     }
//   ]
// }

FAQs

Isn't this just currying one argument to Object.assign?

Yes.

Why can't I just do that myself?

You can.

Then what's the point?

The parameterized type argument helps guide you to get the types of the default objects and the overrides correct. It's not much, but it does help a small bit.

OK, how does it help?

One example: if you add a required field to an interface that is heavily used throughout your test suite, you can just go in and add a value for this new field to its factory's default object and now all of your tests that use the factory will compile.