microsoft / microsoft/TypeScript

Let type identifiers co-exist with import namespace identifiers

オープン
#36,704 コメント 2 件 リアクション 1 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

In Discussion Suggestion
主要言語
Go
スター
111k
フォーク
14.4k
平均マージ
1日 19時間
マージ済み PR(30日)
117

説明

Search Terms

Modules, export, import

Suggestion

It would be convienent if type identifiers could co-exist with import namespace identifiers.

Use Cases

A common pattern is to have a module where the module name is the same as the main type exported by that module.

Examples

Consider this module:

result.ts

export type Result<TError, TValue> =
  | { readonly type: "Ok"; readonly value: TValue }
  | { readonly type: "Err"; readonly error: TError };

export function Ok<TValue>(value: TValue): Result<never, TValue> {
  return { type: "Ok", value };
}

export function Err<TError>(error: TError): Result<TError, never> {
  return { type: "Err", error };
}

// .. more functions to work with the Result type

Now consider a consumer of this moudule:

import * as Result from "./result";

export function itsOk(): Result.Result<string, string> {
  const ok: Result.Result<string, string> = Result.Ok("");
  const err: Result.Result<string, string> = Result.Err("");
  return ok;
}

There are execessive type annotations in this example but the point is that it is annoying ot have to refer to the type Result as Result.Result. I would like to refer to the type as only Result but still have functions related to the module in a Result namespace.

I was reading about the new import type syntax in 3.8 and thought I might get away with something like this:

import * as Result from "./result";
import type { Result } from "./result";

export function itsOk(): Result<string, string> {
    const ok: Result<string, string> = Result.Ok("")
    const err: Result<string, string> = Result.Err("")
    return ok;
}

This fails because there are duplicate identifiers. Typescript does allow duplicate identifiers that live either 100% in the type world or 100% in the concrete world. But imported namespace objects (import * as) lives in both worlds so it does not currently work. Specifically namespace object can contain both types and concrete things.

However I think typescript should be able to infer from usage if I'm referring the type or the namespace when using it in a place where types can be used. If what is referenced could be found by looking at the usage then duplicate identifiers could be allowed. I believe some other languages does it this way.

In this example the type used does not have a dot so it is referring to the imported type rather than the imported namespace.

const ok: Result<string, string> = ..

In this example the type used has a dot so it is referring to the namespace object.

const ok: Result.OtherType = ..

I think this is not related to the ECMA standard for modules and import/export but rather something typescript decide how to handle because it is fully in the "type world" which gets erased when emitted to js.

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, etc.)
  • This feature would agree with the rest of TypeScript's Design Goals.

コントリビューションガイド

コントリビューションガイドを開く

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

調査の方向性

まず issue にある 2 つの import 例を再現し、TypeScript が修飾されていない型名とドット区切りの namespace 名をどのように解決するかを比較します。関係する型チェックと識別子解決の挙動を追跡します。型と import namespace が同じ名前を共有でき、既存の namespace メンバーと出力される JavaScript が変更されないことが完了の条件です。

索引モデルが issue の本文から書いたものです。

評価

技術スタック
typescript
領域
compilers
issue の種類
機能追加
難易度
5/5
見積もり時間
1週間以上
活発さ
停滞
明瞭さ
明確に書かれている
初心者へのやさしさ
25/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。