Creating a package exclusively for types on NPM: A step-by-step guide

I'm looking to set up a package (using either a monorepo or NPM) that specifically exports types, allowing me to easily import them into my project. However, I've run into some issues with my current approach.

import type { MyType } from '@acme/types'

The structure of my project is as follows:

package.json
index.d.ts

In the index.d.ts file, I have defined the following type:

export type MyType = {
  name: string
}

And this is how my package.json looks like:

{
  "name": "@acme/types",
  "main": "./index.d.ts",
  "types": "./index.d.ts",
  "exports": {
    ".": {
      "default": "./index.d.ts",
      "import": "./index.d.ts",
      "types": "./index.d.ts"
    },
    "./package.json": "./package.json"
  }
}

Despite setting up everything correctly, when I try to import my type, I encounter the following error:

File '/Users/acme/packages/types/index.d.ts' is not a module. ts(2306)

I even attempted renaming index.d.ts to index.ts, but unfortunately, that didn't resolve the issue either.

Answer №1

For in-depth information on the topic, refer to the TypeScript handbook's section on Publishing Declaration Files. Additionally, explore the DefinitelyTyped repository for a plethora of examples.


In a straightforward scenario like the one outlined in your query, the essential components required within the provider package are:

  1. The type declaration files, notably an entrypoint declaration file named index.d.ts.

  2. The basic criteria to fulfill the Node.js module definition include having a package.json manifest file with the necessary fields: name and version

Hence, assuming your provider package directory is situated at ./provider, the required files should be structured as follows:

./provider/package.json:

{
  "name": "@acme/types",
  "version": "0.1.0"
}

./provider/index.d.ts:

export type MyType = {
  name: string;
};

An important note from the TS handbook page linked above emphasizes that if your main declaration file is named index.d.ts and resides at the root of the package, you might not need to specify the types property explicitly, although it's recommended.

It would be wise to define the field explicitly rather than relying solely on auto-resolution behavior:

./provider/package.json:

{
  "name": "@acme/types",
  "version": "0.1.0",
  "types": "./index.d.ts"
}


This addresses the query posed — but I'll also provide a sample consumer package along with steps for replication purposes.

You can either manually recreate each example file in your filesystem by copying + pasting them or utilize the provided script in your browser's JS console to download a zip archive containing the project structure:

(() => {
  function createBase64DataUrl(mediaType, b64Str) {
    return `data:${mediaType};base64,${b64Str}`;
  }

  function download(url, fileName) {
    const a = document.createElement("a");
    a.href = url;
    a.download = fileName;
    a.click();
    a.remove();
  }

  const zipArchiveData = "..."; // Base64 data truncated
  const dataUrl = createBase64DataUrl("application/zip", zipArchiveData);
  download(dataUrl, "so-75850348.zip");
})();

If the consumer package directory is placed at ./consumer, it could begin with this rudimentary package file:

./consumer/package.json:

{
  "name": "consumer",
  "version": "0.1.0"
}

To start off, install TypeScript and the provider types package as dev dependencies:

$ cd ./consumer
$ npm install --save-dev typescript ../provider

added 2 packages, and audited 4 packages in 616ms

found 0 vulnerabilities

You could have installed each package separately using distinct commands:

npm install --save-dev typescript
npm install --save-dev ../provider

Following installation, the package.json will include these dependencies:

{
  "name": "consumer",
  "version": "0.1.0",
  "devDependencies": {
    "@acme/types": "file:../provider",
    "typescript": "^5.0.2"
  }
}

To utilize the types in code, let's craft a simple TypeScript file leveraging the types from the package:

./consumer/index.ts:

import type { MyType } from "@acme/types";

const obj: MyType = { name: "foo" };

console.log(obj);

Subsequently, add an npm script to the package.json for compiling the TypeScript file with default compiler settings, naming the script compile:

{
  "name": "consumer",
  "version": "0.1.0",
  "devDependencies": {
    "@acme/types": "file:../provider",
    "typescript": "^5.0.2"
  },
  "scripts": {
    "compile": "tsc index.ts"
  }
}

Typically, configuring the compiler behavior for your project using a TSConfig is recommended.

Finally, compile the file and run it:

$ npm run compile && node index.js

> [email protected] compile
> tsc index.ts

{ name: 'foo' }

The compilation proceeds smoothly without errors, and the file executes as intended.

Note that I'm utilizing Node LTS version v18.15.0 while drafting this response.

$ node --version
v18.15.0

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Issue with Formgroup in Angular Reactive Form - Validation not functioning as expected

I am working with a form group which is defined below: get createItem(): FormGroup { return this.formBuilder.group({ name: ['', Validators.required], email: ['', Validators.required], mobile: ['', V ...

React Native is encountering an issue as it cannot locate the specified file or directory: 'appuildintermediatesmerged_manifestsdebugAndroidManifest.xml'

Upon utilizing React Native version 0.61.5, encountering an error after the installation of @react-native-community/cli and executing react-native run-android: info Running jetifier to migrate libraries to AndroidX. You can disable it using "--no-jetifi ...

What is the best way to define multiple variables in ionic 2 using Angular2 and TypeScript?

I'm brand new to working with ionic2/Angular2/Typescript. My project involves creating a wheel with eight slices, but I'm struggling with how to declare multiple variables. In JavaScript, I've declared them like this: function rand(min, max ...

What restrictions prevent the use of npm packages in a Meteor project?

Incorporating a npm package into my meteor project is something I need to do (e.g. the 'moment' package). To achieve this, I initiated the following command: meteor npm install --save moment . This led to an update of the dependencies in package ...

Angular - Using HttpClient for handling POST requests

The example provided in the official Angular HttpClient documentation demonstrates how to make a POST request to a backend server. /** POST: add a new hero to the database */ addHero (hero: Hero): Observable<Hero> { return this.http.post<Hero&g ...

Be cautious when installing Cordova on a Mac device

During the installation of Cordova through npm, I encountered the following warning message: npm WARN engine <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="760e1b1a14031f1a121304364458445847">[email protected]</a> ...

Is it possible to locate a package's peer dependencies on the website www.npmjs.com?

As I work on a project with approximately 50 packages installed through NPM, I am facing the task of updating most of these packages after neglecting them for several months. This has led to mismatching peer dependencies that need to be sorted out. To reso ...

Show an array of arrays using a visual table representation

I am working with an Array of arrays in my data, and they are structured like this : Now, I am trying to showcase this array in a table, but all I am getting is a blank page. Here is the HTML code for the table (I have included only the first column' ...

Create HTML content, convert it into a Word document, and enable users to download it onto their device

Can someone please assist me in using html-docx-js with node.js? I found information on the npm site (https://www.npmjs.com/package/html-docx-js) regarding this. Below is the code snippet provided: var converted = htmlDocx.asBlob(content); saveAs(convert ...

What is the method for obtaining a literal type through a function parameter to use as a computed property name?

Can you help me with this code snippet? const fn = (name: string) => { return { [name]: "some txt" }; }; const res = fn("books"); // books or any other string The type of res recognized by TS is: const res: { [x: string]: string ...

Are you looking for straightforward dynamic directives that come with dynamic controllers and a scope?

Feeling like I have a simple problem to solve here. Working within the confines of a TypeScript + Angular application. Within a controller, I've got an array of similar directives that I want to utilize. These are essentially the panels strewn throug ...

Unable to utilize Google Storage within a TypeScript environment

I'm encountering an issue while attempting to integrate the Google Storage node.js module into my Firebase Cloud functions using TypeScript. //myfile.ts import { Storage } from '@google-cloud/storage'; const storageInstance = new Storage({ ...

Is there a way to implement depth-first retrieval in rxjs using the expand method?

Currently, I am engaged in a project utilizing Angular 7, Typescript, and RxJS 6.3.3. In this project, I am working with RxJS Observables and relevant operators to handle hierarchical collections of objects obtained from an http server that interfaces with ...

Strange activities observed during the management of state in react hooks, where the splice() function ends up eliminating the

My current setup involves maintaining a state to handle the addition of new JSX elements: const [display, setDisplay] = useState<IDisplay>({ BookingFormDropDown: [], } ); I have a function in onClick() which adds an elem ...

Puppeteer never seems to stop griping about chromium

After installing Puppeteer(V2.0.0), I decided to skip the chromium installation by using PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true. However, after the puppeteer installation, I noticed that there is no .local-chromium folder under the puppeteer folder inside t ...

Just starting out with React and encountering the error: Invalid element type, a string was expected

I seem to be going in circles with the following issue as I try to load the basics of a React app into the browser. An error message stating 'Element type is invalid: expected a string (for built-in components) or a class/function (for composite c ...

Error: npm was not located in the Visual Studio Code terminal

Each time I attempt to execute "npm" from the VS Code terminal, I encounter the following error message: "The term 'npm' is not recognized as the name of a cmdlet, function, script file, or operable program." This command worked perfectly fine on ...

Issue encountered during npm installation (fatal error: invalid object f18e4d058698a689943db9cb41f767efbc2c85ed)

Recently I obtained code from a repository on GitHub and attempted to install it. However, encountered errors during the installation process: terrylai@Terrys-MacBook-Pro:~/copay$ npm install npm ERR! git rev-list -n1 f18e4d058698a689943db9cb41f767efbc2c ...

Having trouble with NVM not working correctly in Ubuntu 21.04 Terminal?

Lately, I've been facing challenges with updating my Node.js version, and one method I tried was using node version manager. After downloading the install_nvm.sh file with the command curl -sL https://raw.githubusercontent.com/nvm-sh/nvm/v0.38.0/insta ...

Bring in exclusively typescript module declarations

In my various React projects, I find myself constantly declaring the same typescript modules, such as fonts.d.ts: declare module "*.woff"; declare module "*.woff2"; or images.d.ts: declare module "*.jpg" { const src: string ...