microsoft / microsoft/TypeScript

Importing a type with the same name as a namespace import, ideally alongside it

Open
#54,990 5 comments 6 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Awaiting More Feedback Suggestion
Dominant language
Go
Stars
111k
Forks
14.4k
Avg merge
1d 19h
Merged PRs (30d)
117

Description

Suggestion

🔍 Search Terms

import, type, module, namespace import,

✅ Viability Checklist

My suggestion meets these guidelines:

  • This wouldn't be a breaking change in existing TypeScript/JavaScript code
  • This wouldn't change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
  • This feature would agree with the rest of TypeScript's Design Goals.

⭐ Suggestion

Being able to do write something like this:

import * as Foo, type { Foo } from './Foo.js';

A more conservative request would be:

import * as Foo from './Foo.js';
import type { Foo } from './Foo.js';

📃 Motivating Example

import * as Foo, type { Foo } from './Foo.js';

// no need to write Foo.Foo    vvv
const someFunction = (someFoo: Foo) => ...

💻 Use Cases

It's a common pattern in functional programming to substitute classes with modules. this has several advantages (tree-shakability, no this binding, etc.).

These modules bundle functions which operate on some data and a type that identifies this data.

export type Foo = [string, (a: any) => unknown];

export const unit = (): Foo => ['', (x: any) => x];

export const concat = (self: Foo, a: Foo) =>
    [self[0] + a[0], (x: any) => a[1](self[1](x))];

The problem is that when you need to mention the type of the data when it's imported as a namespace, you find yourself repeating the name twice:

import * as Foo from './Foo.js';

const someFunction = (someFoo: Foo.Foo) => ...

On top of looking a little bit awkward, this is really not convenient when the name gets longer, but you don't want to import members directly because a function name like concat is likely to create collisions and aliasing it to concatFoo is a chore and can make the imports section of a file very noisy and unreadable.

I encountered this problem in my one code but also in libraries like fp-ts and Effect.

A module can also export types that it requires, like input types, so the more ambitious request would not only be useful for mentioning the "constructor" type, although this use case is less important.

A workaround is to export an alias (something like Foo.Of or Foo.Self):

export { Foo as Self }

If we are talking about a library, this is something the maintainer needs to support and it's not that self-explanatory.

Another option is to create a type alias in the importing file

import * as Foo from './Foo.js';
type Foo = Foo.Foo;

If our type requires generics and type constraints, this becomes a real chore on top of requiring maintenance.

It would be consistent with the behaviour of the latter workaround to support the more conservative request. At current it yields the error Duplicate identifier 'Foo', which is a little weird since values and types live in different worlds.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

No source file, test, or compiler entry point is named. Start by reviewing the proposed namespace and type-import examples and the existing duplicate-identifier behavior. Done means agreeing on and implementing the supported import form, with coverage for the motivating examples and no change to emitted JavaScript.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
compilers
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
28/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.