#13411·umi

auto-import broken for runtime hooks (useModel/useIntl) due to `export *` chain in index.d.ts

Author: zhangheng0317Created Aug 12, 2026Updated Aug 13, 2026

Bug Description

When using umi, editor auto-import (VSCode built-in TypeScript language service) cannot auto-import runtime hooks like useModel, useIntl, useAccess, etc. from "umi". The user has to manually type import { useModel } from "umi" every time.

Type checking works fine -- this is purely an auto-import / IntelliSense issue.

Expected Behavior

Typing useModel or useIntl in a .tsx file should suggest auto-importing it from "umi".

Actual Behavior

Typing useModel shows no auto-import suggestion from "umi", or only suggests importing from @@/plugin-model / @@/plugin-locale (internal generated paths), not from the public "umi" entry.

Root Cause

The root cause is that index.d.ts uses two layers of wildcard re-export:

typescript
// node_modules/umi/index.d.ts
// @ts-ignore
export * from "@@/exports";          // layer 1: export *
export type { IApi, ... } from "@umijs/preset-umi";
export * from "./dist";              // layer 2: export *

The VSCode / TypeScript auto-import engine does not recursively traverse export * chains to build its "symbol -> module" index. As a result:

  • useModel is exported from @@/plugin-model -> re-exported via export * in @@/exports.ts -> re-exported via export * in umi/index.d.ts
  • TypeScript type-checks this correctly (the types are resolved)
  • But the auto-import engine cannot trace this 2-hop export * chain back to "umi"

This is a known limitation of the TS language service's auto-import provider (see microsoft/TypeScript#43313). In umi's case the problem is amplified because the @@/exports target is a path-mapped, auto-generated file.

Current Workarounds (both have drawbacks)

1. Override tsconfig.json paths to point umi directly at .umi/exports.ts:

json
{
  "compilerOptions": {
    "paths": {
      "umi": ["./src/.umi/exports.ts"]
    }
  }
}
  • [+] Fixes auto-import for runtime hooks
  • [-] Loses build-time types (IApi, IRoute, defineConfig, Service, run, etc.) from ./node_modules/umi/dist and @umijs/preset-umi. These are essential for plugin development (plugins/*.ts) and config.ts.

2. Point umi to a manually-maintained bridge file + node_modules:

json
{
  "compilerOptions": {
    "paths": {
      "umi": ["./types/umi-bridge.d.ts", "./node_modules/umi"]
    }
  }
}

with a bridge file that uses explicit named re-exports (which the auto-import engine can parse):

typescript
// types/umi-bridge.d.ts  (manual maintenance required!)
export { useModel, Provider } from "@@/plugin-model";
export { useIntl, SelectLang, FormattedMessage } from "@@/plugin-locale";
// ... must manually sync with src/.umi/exports.ts every time umi regenerates it
export type { IApi, IRoute } from "@umijs/preset-umi";
export * from "umi/dist/service/service";
  • [+] Works for both auto-import and build-time types
  • [-] Fragile and unmaintainable -- requires manual sync with the auto-generated exports.ts.

Suggested Improvement

Consider generating the runtime exports in index.d.ts (or a sibling .d.ts) using explicit named re-exports instead of export *, so the TS auto-import engine can index them directly.

Since umi already generates src/.umi/exports.ts with full knowledge of all enabled plugins, the codegen could emit this explicit list into a type entry:

typescript
// node_modules/umi/index.d.ts  (or generated sibling)
// Keep explicit named exports for runtime hooks -- auto-import friendly
export { defineApp } from "@@/core/defineApp";
export { Access, useAccess, useAccessMarkedRoutes } from "@@/plugin-access";
export { useAntdConfig, useAntdConfigSetter } from "@@/plugin-antd";
export { useIntl, SelectLang, FormattedMessage } from "@@/plugin-locale";
export { Provider, useModel } from "@@/plugin-model";
export { useRequest, request } from "@@/plugin-request";
export { history, Link, Outlet, useNavigate } from "@@/renderer-react";

// Build-time types still via export *
export type { IApi, IRoute, IUtoopackUserConfig } from "@umijs/preset-umi";
export * from "./dist";

Environment

  • umi version: 4.6.80
  • OS: Windows 10
  • Editor: VSCode (latest)
  • tsconfig.json:
json
{
  "extends": "./src/.umi/tsconfig.json",
  "compilerOptions": {
    "paths": {
      "@/*": ["./src/*"],
      "@@/*": ["./src/.umi/*"],
      "umi": ["./node_modules/umi"],
      "umi/typings": ["./src/.umi/typings"]
    }
  }
}

Reproduction

  1. npx create-umi@latest (React + antd + model + locale plugins)
  2. Start dev server (umi dev) so src/.umi/exports.ts is generated
  3. Open any .tsx file, type useModel or useIntl
  4. Observe: no auto-import suggestion from "umi"