Skip to main content

Avoid Using Wildcard Imports

Medium
Best PracticesMaintainability

What is it?

This practice warns against the use of wildcard imports in TypeScript. Wildcard imports, such as using "import * as", pull in all exported members from a module, making it unclear which specific exports are being utilized. This ambiguity can make code harder to read, maintain, and refactor.

Why apply it?

Explicitly listing the imported members: • Improves code readability by making dependencies clear. • Reduces the risk of namespace collisions. • Helps maintainers understand the module dependencies without having to inspect the imported module itself. • Limits the exposure of internal module details by only importing what is necessary.

How to Fix it?

Replace wildcard imports with explicit named imports. List exactly what you need from the module rather than importing everything.

Examples

Example 1:

Negative

Incorrect implementation that violates the practice.

import * as Imported from "aModule";  // Noncompliant

function processData(data: Imported.aType): void {
if (Imported.aFunction(data)) {
console.log(Imported.aConstant);
} else {
console.error("Processing failed!");
}
}

const item: Imported.aType = { key: "value" };
processData(item);

Example 2:

Positive

Correct implementation following the practice.

// In util.ts
export const helper = (): string => {
return "Helper function executed";
};

export const version = "1.0.0";

export class UtilClass {
log(message: string): void {
console.log("Log:", message);
}
}

// In index.ts
import { helper, UtilClass } from "./util";

console.log(helper());
const utilInstance = new UtilClass();
utilInstance.log("Initialization complete");

Negative

Incorrect implementation that violates the practice.

import * as ConfigModule from "./config";  // Noncompliant

function initApp(config: ConfigModule.ConfigType): void {
const logger: ConfigModule.Logger = new ConfigModule.Logger();
logger.info("Application initialization started.", config);
// Additional initialization logic...
logger.info("Application successfully initialized.");
}

const config = { env: "production", debug: false, apiEndpoint: "https://api.example.com" };
initApp(config);

Example 3:

Positive

Correct implementation following the practice.

import { Logger, ConfigType } from "./config";

function initApp(config: ConfigType): void {
const logger: Logger = new Logger();
logger.info("Application initialization started.", config);
// Additional initialization logic...
logger.info("Application successfully initialized.");
}

const config = { env: "production", debug: false, apiEndpoint: "https://api.example.com" };
initApp(config);

Negative

Incorrect implementation that violates the practice.

// In util.ts
export const helper = (): string => {
return "Helper function executed";
};

export const version = "1.0.0";

export class UtilClass {
log(message: string): void {
console.log("Log:", message);
}
}

// In index.ts
export * from "./util"; // Noncompliant

// Consumers now receive unintended exports like 'version'

Example 4:

Positive

Correct implementation following the practice.

import { aType, aFunction, aConstant } from "aModule";

function processData(data: aType): void {
if (aFunction(data)) {
console.log(aConstant);
} else {
console.error("Processing failed!");
}
}

const item: aType = { key: "value" };
processData(item);