The consequences of exporting raw .ts files instead of .d.ts files for module type declarations

In a typical TypeScript module, you will find a 'src' directory containing TypeScript source code files. The module compiles these sources using 'tsc -d --outDir dist' to create the 'dist' directory and sets specific package metadata to ensure compatibility with both Node.js runtime and TypeScript compiler.

{
  "main": "dist/index.js",
  "types": "dist/index.d.ts",
  "files": ["dist"]
}

Adding source-maps and original source code to packages can facilitate debugging.

Considering the introduction of Project References and the compiler option '--declarationMap', it is recommended for modules to provide declaration map files as well. This allows IDEs to navigate from module API calls directly to the implementation, rather than just the generated '.d.ts' files.

Thus, a module is expected to contain:

  • Transpiled '.js' files for runtime
  • Original '.ts' files for debugging
  • Declaration files '.d.ts' for TypeScript compiler
  • Declaration map files '.d.ts.map' for IDE tooling

However, the complexity of this setup raises the question - what if we eliminate '.d.ts' and '.d.ts.map' files and ship the original TypeScript sources instead?

{
  "main": "dist/index.js",
  "types": "src/index.ts",
  "files": ["src", "dist"]
}

Some potential downsides to this approach include:

  • Increased workload for TypeScript compiler when compiling projects dependent on the module, as it needs to parse full '.ts' sources instead of concise '.d.ts' files, potentially resulting in slower builds.

  • Similar impact on IDEs like VSCode, which would need to parse full '.ts' sources instead of optimized '.d.ts.map' files for faster processing.

Additionally, there is a distinction between '.d.ts' and '.ts' files - the former exports declarations only, while the latter exports definitions. It raises questions about how TypeScript handles multiple instances of the same module within the dependency tree.

Considering these factors, are there any valid arguments against using original '.ts' files for type declarations?

Answer №1

When it comes to shipping packages, including both source-maps and the original source code is often a common practice.

While this is partially true, it's important to note that a source map already contains your source code. This enables DevTools to reconstruct the original source from minified JavaScript when only the source map is available.

One downside of including source code is the impact on package size. Declaration files are lightweight and many libraries can be described in a single file of under 100 lines of code.

However, a small API surface does not necessarily mean less source code. A project may consist of numerous modules but have a compact public API. By using a *.d.ts file to describe it, consumers can save space on their devices.

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

The subcategory was not factored into my npm package

In my npm module 'ldap-pool', I'm facing an issue where the '@types/ldapjs' package, which is a dependency along with 'ldapjs', does not get installed when I add 'ldap-pool' to another project. This particular s ...

Retrieve the current state of the toggle component by extracting its value from the HTML

I have a unique component that consists of a special switch and several other elements: <mat-slide-toggle (change)="toggle($event)" [checked]="false" attX="test"> ... </mat-slide-toggle> <p> ... </p> F ...

In ReactJS, the way to submit a form using OnChange is by utilizing the

Is there a way to submit a form using Onchange without a button? I need to fire the form but can't insert routes as it's a component for multiple clients. My project is built using react hook forms. const handleChange = (e: any) => { c ...

Struggling to implement the .map method with TypeScript?

I'm currently grappling with incorporating TypeScript into my .map method and encountering the error message below. Additionally, I'm uncertain about the meaning of the 'never' keyword. TS2339: Property 'fname' does not exist ...

Accessing instance variables from a chained observable function in Angular 2/Typescript

Currently, I am utilizing Angular2 along with Typescript. Let's assume that there is a dummy login component and an authentication service responsible for token authentication. In one of the map functions, I intend to set the variable authenticated as ...

Locating the source and reason behind the [object ErrorEvent] being triggered

I'm facing an issue where one of my tests is failing and the log is not providing any useful information, apart from indicating which test failed... LoginComponent should display username & password error message and not call login when passed no ...

What are the benefits of using material-ui@next without the need for

Thinking about creating a project using material-ui@next, but trying to avoid using withStyles. However, encountering issues with the draft of TypeScript that includes the decorator @withStyles. This leads to one question - is it possible to use material ...

Vuejs fails to properly transmit data

When I change the image in an image field, the new image data appears correctly before sending it to the back-end. However, after sending the data, the values are empty! Code Commented save_changes() { /* eslint-disable */ if (!this.validateForm) ...

Determining data types through type guarding in Typescript

interface A = { name: string; ... }; interface B = { name: string; ... }; interface C = { key: string; ... }; type UnionOfTypes = A | B | C | ...; function hasName(item: UnionOfTypes) { if ("name" in item) { item; // typescript knows ...

Resolving the Duplicate Identifier Issue in Ionic 2 with Firebase Integration

I'm struggling with setting up ionic2 + Firebase 3. Following a tutorial, I installed Firebase and Typings using the commands below: npm install firebase --save npm install -g typings typings install --save firebase However, when I try to run ioni ...

Is there a way to receive a comprehensive report in case the deletion process encounters an error?

Currently, I am performing a delete operation with a filter based on 2 fields: const query = await Flow.deleteOne({ _id: flowId, permissions: currentUser!.id, }); After executing the delete operation, I inspect the query object to determine its su ...

The correct method for handling arrays with overlapping types and narrowing them down again

When working with arrays containing different types in TypeScript, I often encounter issues with properties that are not present on all types. The same challenge arises when dealing with various sections on a page, different user roles with varying proper ...

What is the process for defining a type that retrieves all functions from a TypeScript class?

Imagine having a class called Foo class Foo { bar(){ // do something } baz() { // do something } } How can you define a type ExtractMethods that takes a class and returns an interface or type containing the class methods? For example: t ...

What is the process for transferring a Pulumi Output<T> to the container definition of a task in ECS?

When creating a generic ECS service that deals with dynamic data, it is important to note that the containerDefinition within a Task Definition must be provided as a single valid JSON document. The code snippet for this setup looks like: genericClientServi ...

Different combinations of fields in Typescript types

Take a look at this defined type: type MyType = | { a: number } | { b: number } | { c: number } | ({ b: number } & { c: number }); The goal is to prevent the combination of 'a' with either 'b' or 'c'. const o1: ...

Angular Service singleton constructor being invoked multiple times

I have been facing an issue with using an app-wide service called UserService to store authenticated user details. The problem is that UserService is being instantiated per route rather than shared across routes. To address this, I decided to create a Core ...

React TypeScript - creating a component with a defined interface and extra properties

I'm completely new to Typescript and I am having trouble with rendering a component and passing in an onClick function. How can I properly pass in an onClick function to the CarItem? It seems like it's treating onMenuClick as a property of ICar, ...

Type of JavaScript map object

While exploring TypeScript Corday, I came across the following declaration: books : { [isbn:string]:Book}={}; My interpretation is that this could be defining a map (or dictionary) data type that stores key-value pairs of an ISBN number and its correspon ...

Expand the size of the imported gltf model within Three.js

After successfully loading a 3d model with a gltf extension using the GLTFLoader in Three.js, I encountered a new challenge. I needed to adjust the dimensions of the model dynamically when the window is resized, based on the values of window.innerWidth and ...

When object signatures match exactly, TypeScript issues a warning

I am facing an issue with typescript while trying to use my own custom type from express' types. When I attempt to pass 'Request<ParamsDictionary, any, any, ParsedQs, Record<string, any>>' as a parameter of type 'Context&a ...