What is the process for setting up custom global interfaces in TypeScript using .d.ts files?

I'm currently facing an issue in my ReactJS project using Webpack2 and TypeScript. Everything is functioning perfectly except for one thing - I've been struggling to move my self-written interfaces into separate files so they are accessible throughout the application.

Initially, I had all interfaces defined in files where they were being used, but as the project grew, I needed some interfaces to be shared among multiple classes, leading to complications. Despite modifying my tsconfig.json and relocating the files, both my IDE and Webpack continue to throw errors like "Could not find name 'IMyInterface'."

Here is a snippet from my current tsconfig.json:

{
  "compilerOptions": {
    // Compiler options here
  },
  // Exclude paths here
}

The tsconfig.json file resides in the root directory, source code in the ./src folder, and custom .d.ts files under ./typings, included in the typeRoots.

I have tested this setup with TypeScript versions 2.1.6 and 2.2.0 without success.

A possible solution involves moving the typings directory into src and then importing interfaces like so:

import {IMyInterface} from 'typings/blah'
. However, this approach does not feel right to me as it's unnecessary complexity. I want these interfaces to be seamlessly available across the entire application.

For example, a sample interface app.d.ts looks like:

interface IAppStateProps {}
interface IAppDispatchProps {}
interface IAppProps extends IAppStateProps, IAppDispatchProps {}

Do I need to export them or declare? Do I have to enclose them in a namespace?

Update (October 2020)

Given the ongoing popularity of this question, let me elaborate on the solution further.

Answer №1

It is strongly advised to avoid relying on "Magically available interfaces" or global types, as this practice is generally considered outdated and should only be used for legacy purposes. Instead, when writing your own code, it is recommended to refrain from using ambient declaration files (such as d.ts files).

For defining interfaces and types in the code you are actively working on, it is best practice to utilize plain .ts files.

In Typescript, there are two main types of .ts files: 'scripts' and 'modules'. Anything declared in a 'script' file will have global scope, making it accessible throughout the entire application if included in the compilation process through various methods like ///<reference path="">, files:[], includes:[], or by default using **/*.ts in the tsconfig.json.

On the other hand, items defined within a 'module' file will be private to that module unless explicitly exported for use in other modules via import statements.

To differentiate between a 'script' and a 'module' in a .ts file, simply look for the presence of import/export statements. If these statements are present, the file is considered a 'module'; otherwise, it functions as a global 'script'.

If your interfaces are not behaving as expected and seem to be restricted to a specific module, chances are you accidentally introduced import or export statements in your declarations, converting them into a module. To maintain global accessibility for your interfaces, ensure that no import or export statements are used within the file.

Answer №2

When working with global interfaces, it is important to remember that they are not "Magically available interfaces", but rather "global" interfaces.

In my .d.ts file, I extend the global Window interface in the following way:

export {};

declare global {
    interface Window {
        // This is just for IDE and/or TS-compiler purposes (defined in a .js file).
        myGlobalVariable: any;
    }
}

We can also create custom-global-interfaces using the same technique instead of extending existing ones.

For example:

import React from 'react';

declare global {
    interface MyGlobalInterface {
        myComponentField: React.Component;
    }
}

It's worth noting that .d.ts files do not generate output, so we can import any module as long as it is installed in the package.json.

In the above example, the export {}; line is not necessary because there is an import statement. The rule required at least one import or export at the time of writing.

Lastly, the name(s) and location(s) of the .d.ts files do not matter, but personally, I prefer placing the globals.d.ts file next to the root js/ts file of the project to ensure it is loaded first.

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

Using TypeScript with React: Automatically infer the prop type from a generic parameter

I've developed a component that retrieves data from an API and presents it in a table. There's a prop that enables the fetched value to be displayed differently within the table. Here's how I currently have the prop types set up: // T repres ...

Upgrade your development stack from angular 2 with webpack 1 to angular 6 with webpack 4

Recently, I have made the transition from Angular 2 and Webpack 1 to Angular 6 and Webpack 4. However, I am facing challenges finding the best dependencies for this new setup. Does anyone have any suggestions for the best dependencies to use with Angular ...

The element 'stripe-pricing-table' is not a recognized property of the 'JSX.IntrinsicElements' type

I am currently trying to incorporate a pricing table using information from the Stripe documentation found at this link. However, during the process, I encountered an issue stating: "Property 'stripe-pricing-table' does not exist on type &ap ...

Combining results from multiple subscriptions in RxJS leads to a TypeScript compiler error

I am utilizing an Angular service that provides a filterObservable. To combine multiple calls, I am using Rx.Observable.zip(). Although it functions as expected, my TypeScript compiler is throwing an error for the method: error TS2346: Supplied paramete ...

The utility of commander.js demonstrated in a straightforward example: utilizing a single file argument

Many developers rely on the commander npm package for command-line parsing. I am considering using it as well due to its advanced functionality, such as commands, help, and option flags. For my initial program version, I only require commander to parse ar ...

Experiencing an issue with type error when transitioning syntax from using require to import

After transitioning from require in CommonJS syntax to import in ES Module syntax, I encountered an error. I decided to develop a todo-app using Node.js, TypeScript, and MySQL. To start off, I wrote the initial code snippets below: // db.ts export {}; co ...

Handling Promises in Angular 1 App using Typescript ES6/2015

Currently, I am working on an Angular 1.5 application that utilizes Typescript. My main concern is finding the most efficient way to handle ng.IPromise compared to Promise (ES6 promise). Personally, I would prefer to solely deal with the ES6 Promise type. ...

Streamline imports with Typescript

Is there a way to import modules with an alias? For example, I have an angular service in the folder common/services/logger/logger.ts. How can I make the import look like import {Logger} from "services" where "services" contains all my services? I've ...

Tips for creating a recursive string literal type in Typescript

I need to create a type that represents a series of numbers separated by ':' within a string. For example: '39:4893:30423', '232', '32:39' This is what I attempted: type N = `${number}` | '' type NL = `${ ...

Enumerated types in Typescript: access the values

Below is a flagged enum I have: enum PermissionEnum { SU = 1 << 0, // 1 Administrator = 1 << 1, // 2 User = 1 << 2 // 4 } If the value given is 6, how can I achieve: An array of strings -> ['Adm ...

Updating the node startup file with Visual Studio 2015 using NodeJS/Typescript

Encountering a persistent error: Error Code: TS5055 Cannot write file C:/project/dir/server.js' because it would overwrite the input file. Project: TypeScript/JavaScript Virtual Projects Even after renaming my entry filename to nodeserver.js, the ...

Encountered an error stating 'name' property is undefined while using @input in Angular 2

Everything seems to be set up correctly, but I'm encountering an error in the browser console that says "Cannot read property 'name' of undefined": This is how my media.component.ts file is structured: import { Component, Input } from &apo ...

ERROR Error: Uncaught (in promise): ContradictionError: The variable this.products is being incorrectly identified as non-iterable, although it

Seeking a way to extract unique values from a JSON array. The data is fetched through the fetch API, which can be iterated through easily. [please note that the product variable contains sample JSON data, I actually populate it by calling GetAllProducts( ...

Is there a way to access every item that includes a particular attribute and attribute term within the woocommerce-rest-api?

Struggling to retrieve products that have the "x-attribute" and "x-attribute-term" using Node.js with the WooCommerce REST API library from here. I've explored solutions on stackoverflow and other sites but none seem to work. Atte ...

Embrace the power of Angular2: Storing table information into

Custom table design Implement a TypeScript function to extract data from an array and populate it into a stylish table. ...

Guide to incorporating third-party libraries in Angular

Greetings, I have a common question regarding Angular and utilizing third-party libraries. As someone who does not frequently work with Typescript/Frontends, I am encountering an issue with Angular. Specifically, I am attempting to incorporate the node-htm ...

I'm encountering an issue with my React 18 application using TypeScript: the module './App' cannot be found

Encountering an issue while attempting to update to react 18. I'm curious if this problem is related to my file types. I am using Typescript, so do both the app and index files need to have a .tsx extension? Both the app and index files are located ...

Angular data table is currently displaying an empty dataset with no information available

While attempting to display a data table in Angular JS, an issue arose where the table showed no available data despite there being 4 records present. Refer to the screenshot below for visual reference. This is the approach I took: user.component.ts imp ...

Automatic type inference for TypeScript getters

It appears that Typescript infers field types based solely on the private variable of a field, rather than taking into account the getter's return type union (1) or inferring from the getter itself (2): test('field type inference', () =& ...

Angular 2 - Ensuring service executes only when boolean condition is met

I am currently dealing with a navigation menu that utilizes the ng2-page-scroll module. When scrolling through the page using hashtag links, I encountered an issue. If I navigate across routes, there is a delay in loading the data. As a result, the servic ...