Skip to content

Redefine how we import Type Extensions in all the plugins so that the imports get removed during compilation, while preserving the type-level extensions. #8164

@alcuadrado

Description

@alcuadrado

Hardhat plugins use Type Extensions to add functionality to existing types.

A Type Extension needs to be reachable by TypeScript for it to take place. If it's in your own codebase, you don't need to do anything special, as in that situation TypeScript evaluates all your files.

When you are distributing a package through npm though, only the imported files of your package, and their transitive dependencies are loaded. If you place a type-extensions.ts file next to your plugin's index.ts file and don't import it in any way, it will be ignored.

Our current recommendation is for plugins to have a top-level

import "./type-extension.ts";

in their index.ts, which works to force TypeScript to apply the extension.

Its drawback is that that import is also present in the compiled index.js, and run when the plugin is loaded without any added benefit.

Instead, we can use this pattern:

export type * from "./type-extensions.ts";

it still forces typescript to apply the type extensions, but it doesn't generate a runtime import.

For this pattern to work, is extremely important that the ./type-extensions.ts file doesn't:

  1. Produce any side effect
  2. Export any type
  3. Has a export type * from "plugin-dependency"; for each plugin you depend on.

The new updated pattern for type extensions should then be:

  • Add export type * from "./type-extensions.ts"; to your plugin's index.ts
  • Do not run any executable code in your ./type-extensions.ts file. Only type-level code is valid.
  • Do not export any type from your type-extension.ts
  • Type-extensions don't need to import the modules they are augmenting. This was an incorrect way to force the .ts file to be treated as a module. Use export {};, or better yet "moduleDetection": "force".
  • Do not export any type from your index.ts, otherwise plugins depending on yours will accidentally re-export it.

To do this, we should:

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status

    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions