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

typescript_scribe

v0.3.5

Published

A lightweight library to infer JavaScript object structures at runtime and generate TypeScript types, helping developers ensure type safety and reduce manual type definitions.

Downloads

2,079

Readme

typescript_scribe

TypeScript GitHub npm npm codecov

Table of Contents

  1. Introduction
  2. Features
  3. Prerequisites
  4. Installation
  5. Basic Usage
  6. Real-World Examples
  7. Advanced Usage
  8. TypeScript Types
  9. Handling Edge Cases
  10. Additional Notes
  11. Known Issues and Limitations
  12. Contributing
  13. License

Introduction

typescript_scribe is a lightweight library that automatically infers the structure of JavaScript objects and generates corresponding TypeScript types. It helps engineers quickly generate type definitions from dynamic data, reducing manual work and improving code quality.

Features

  • Type Inference for Objects and Arrays: Automatically infers types from complex and nested objects or arrays.
  • Date and Promise Handling: Correctly infers Date and Promise objects in JavaScript.
  • Mixed Types and Empty Arrays: Handles arrays with mixed types, returning 'mixed' for accurate representation, and infers empty arrays as ['unknown'].
  • Support for Nested Object Structures: Recursively infers types for deeply nested objects and arrays with ease.
  • TypeScript-First Approach: Generates TypeScript-compatible type definitions without the need for manual intervention.

Prerequisites

  • Node.js: Ensure you have Node.js installed (version 16.x or above recommended).
  • npm: Ensure npm is installed. It comes bundled with Node.js.
  • TypeScript: You should have TypeScript installed and set up in your project.

Installation

npm install typescript_scribe or yarn add typescript_scribe

Basic Usage

Infer Type

Use the inferType function to deduce the structure of your JavaScript object.

import { inferType } from 'typescript_scribe';

const myObj = {
  id: 1,
  name: "Anthony",
  time: new Date(),
  tasks: ["code", "sleep", "repeat"]
};

// Infer the structure of the object
const inferred = inferType(myObj);
console.log(inferred);

// Output:
{
  id: 'number',
  name: 'string',
  time: 'Date',
  tasks: ['string']
}

Generate TypeScript Type

Use generateTypeScriptType to generate a TypeScript type definition based on the inferred structure.

import { generateTypeScriptType } from 'typescript_scribe';

const myObj = { id: 1, name: "Anthony", tasks: ["code", "sleep", "repeat"] };

// Generate a TypeScript type from the object
const tsType = generateTypeScriptType(myObj);
console.log(tsType);

// Output:
type GeneratedType = {
  id: number;
  name: string;
  tasks: string[];
};

Real-World Examples

Handling a Complex API Response

When working with dynamic API responses, typescript_scribe can infer complex nested structures, saving you time on manual type definition.

const apiResponse = {
  user: {
    id: 1,
    name: "John Doe",
    address: {
      city: "New York",
      postalCode: 10001,
    },
    tags: ["admin", "contributor"],
    settings: {
      newsletter: true,
      timezone: "EST",
    },
  },
};

// Infer the structure of the response
const inferredApiResponse = inferType(apiResponse);
console.log(inferredApiResponse);

// Output:
{
  user: {
    id: 'number',
    name: 'string',
    address: {
      city: 'string',
      postalCode: 'number',
    },
    tags: ['string'],
    settings: {
      newsletter: 'boolean',
      timezone: 'string',
    }
  }
}

Inferring Types for Dynamic Form Data

Working with dynamic forms? Let typescript_scribe infer the structure of the collected data for you.

const formData = {
  name: "Jane Doe",
  age: 29,
  preferences: {
    theme: "dark",
    notifications: true,
  },
  items: [
    { id: 1, name: "Item 1", price: 9.99 },
    { id: 2, name: "Item 2", price: 19.99 },
  ],
};

// Generate the TypeScript type from the dynamic form data
const tsFormDataType = generateTypeScriptType(formData, "FormData");
console.log(tsFormDataType);

// Output:
type FormData = {
  name: string;
  age: number;
  preferences: {
    theme: string;
    notifications: boolean;
  };
  items: {
    id: number;
    name: string;
    price: number;
  }[];
};

Advanced Usage

Custom Type Names

You can customize the name of the generated TypeScript type by passing a second argument to generateTypeScriptType.

const myObj = { id: 1, name: "Anthony", tasks: ["code", "sleep", "repeat"] };

const tsType = generateTypeScriptType(myObj, 'CustomType');
console.log(tsType);

// Output:
type CustomType = {
  id: number;
  name: string;
  tasks: string[];
};

Nested Object Structures

typescript_scribe can infer nested objects and arrays, handling complex structures seamlessly.

const complexObj = {
  id: 1,
  profile: {
    name: "Anthony",
    details: {
      age: 35,
      skills: ["TypeScript", "JavaScript", "AWS"]
    }
  }
};

const inferredComplex = inferType(complexObj);
console.log(inferredComplex);

// Output:
{
  id: 'number',
  profile: {
    name: 'string',
    details: {
      age: 'number',
      skills: ['string']
    }
  }
}

const tsComplexType = generateTypeScriptType(complexObj, 'ComplexType');
console.log(tsComplexType);

// Output:
type ComplexType = {
  id: number;
  profile: {
    name: string;
    details: {
      age: number;
      skills: string[];
    };
  };
};

TypeScript Types

The InferredType returned by inferType can be one of the following:

  • 'string', 'number', 'boolean' for primitives.
  • 'Date' for Date objects.
  • 'Promise' for Promise objects.
  • 'null', 'undefined' for null and undefined values.
  • 'mixed' for arrays with mixed types.
  • ['unknown'] for empty arrays.
  • A nested type structure for objects.

Handling Edge Cases

  • Arrays with Mixed Types: If an array contains elements of different types (e.g., [1, 'a', true]), the inferred type will be ['mixed'].
  • Empty Objects and Arrays: Empty objects will return {}, and empty arrays will return ['unknown'].
  • Functions: Functions are not supported and will throw an error if passed into inferType.
  • Circular References: Circular references are not supported and may cause the function to throw an error or behave unexpectedly.

Additional Notes

  • Date Handling: Date objects are inferred as 'Date' to ensure accurate type inference, reflecting their use as a specialized type in TypeScript.
  • Empty Arrays: Empty arrays are inferred as ['unknown'], representing an array with unknown element types.
  • Function Error: If a function is passed to inferType, an error will be thrown because functions are not supported for type inference.

Known Issues and Limitations

  • Currently, circular references are not handled.
  • Very large objects with deep nesting might impact performance.
  • Certain JavaScript-specific objects (e.g., Map, Set) are not yet supported for type inference.

Contributing

Support the project

If you find this library helpful and want to support its development, consider buying me a coffee ☕. Your support fuels my ability to keep building great tools for the community!

How to contribute

  1. Fork the repository.
  2. Create a new branch (git checkout -b feature-branch).
  3. Make your changes and commit them (git commit -m 'Add some feature').
  4. Push to the branch (git push origin feature-branch).
  5. Open a pull request.

For large changes, open an issue first to discuss the potential implementation.

Pipeline

We are currently implementing a GitHub Actions pipeline (work in progress) to automate the testing, linting, and publishing process for the project. This will ensure:

  1. Every pull request is automatically tested using Vitest.
  2. Linting is enforced with XO to maintain code quality.
  3. Successful changes are packaged and prepared for npm publishing.

Future Pipeline Improvements

  • Cross-environment compatibility testing.

Linting with XO

We use XO as our linter because it enforces best practices and works seamlessly with TypeScript and JavaScript projects.

To run the linter:

npm run lint

For more details, check out the official XO documentation.

Testing with Vitest

We use Vitest as the test framework because it's modern, fast, and supports both TypeScript and ES Modules seamlessly.

To run the tests:

npm run test

For more details, check out the official Vitest documentation.

License

This project is licensed under the MIT License.


Return to top