microsoft / microsoft/TypeScript

Future-proof non-aliasing/always-expanding of mapped/intersection/union/etc. types

オープン
#34,556 コメント 0 件 リアクション 28 件 担当者 0 名 GitHub で見る

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

Needs Proposal Suggestion
主要言語
Go
スター
111k
フォーク
14.3k
平均マージ
2日 4時間
マージ済み PR(30日)
132

説明

Search Terms

non-aliasing types

Suggestion

I would like an "officially blessed" way to tell TS if it should give me a type alias, or give me an "expanded" type. (See examples)

Now that this issue has been fixed,
https://github.com/microsoft/TypeScript/issues/32824

the technique I've been using to force TS to not alias a type will break when I migrate to TS 3.6/3.7

Use Cases

In some cases, seeing Mapped1<T>/Intersected1<T>/Unioned1<T> is better for a developer (see examples).

In other cases, seeing the full "expanded" type is better (see examples for Mapped2<T>/Intersected2<T>/Unioned2<T>)

Examples

type Identity<T> = T;

type Mapped1<T> = { [k in keyof T]: [T[k], "mapped"] };
type Mapped2<T> = Identity<{ [k in keyof T]: [T[k], "mapped"] }>;

declare function foo1(): Mapped1<{ x: string, y: number }>;
declare function foo2(): Mapped2<{ x: string, y: number }>;

/*
Aliased, bad
const m1: Mapped1<{
    x: string;
    y: number;
}>
*/
const m1 = foo1();
/*
Non-aliased, good
const m2: {
    x: [string, "mapped"];
    y: [number, "mapped"];
}
*/
const m2 = foo2();

//==============================================================

type Intersected1<T> = T & { hi: string };
type Intersected2<T> = Identity<T & { hi: string }>;

declare function bar1(): Intersected1<{ x: string, y: number }>;
declare function bar2(): Intersected2<{ x: string, y: number }>;

/*
const i1: Intersected1<{
    x: string;
    y: number;
}>
*/
const i1 = bar1();
/*
const i2: {
    x: string;
    y: number;
} & {
    hi: string;
}
*/
const i2 = bar2();

//==============================================================

type Unioned1<T> = T | { hi: string };
type Unioned2<T> = Identity<T | { hi: string }>;

declare function baz1(): Unioned1<{ x: string, y: number }>;
declare function baz2(): Unioned2<{ x: string, y: number }>;

/*
const u1: Unioned1<{
    x: string;
    y: number;
}>
*/
const u1 = baz1();
/*
const u2: {
    hi: string;
} | {
    x: string;
    y: number;
}
*/
const u2 = baz2();

Playground

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.

Related

https://github.com/microsoft/TypeScript/issues/32824#issuecomment-521127740

@weswigham brought up a different way to force TS to not alias a type.

I prefer my Identity<T> trick because it doesn't create a new "temporary" object type.

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

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

はじめの一歩

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

調査の方向性

この issue の mapped、intersection、union の例から始め、次に issue #32824 の関連する議論と、そこからリンクされているコメントを確認してください。TypeScript が、これらの型をエイリアスのままにするか展開するかを制御する、公式にサポートされた方法を備え、示されているユースケースを維持できれば完了です。

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

評価

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

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

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