microsoft / microsoft/TypeScript

Type Assertion for Function Parameters

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

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

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

説明

🔍 Search Terms

"function parameter", "type assertion"

✅ Viability Checklist
⭐ Suggestion

I don't know whether some one had proposed this, but at least I have not found any in my searches.

A simple new syntax like this:

function(e: Type as AssertType) {

}
(e: Type as AssertType) => {

}
📃 Motivating Example

Let's take Event and CustomEvent as an example.

Now we have a class inheriting from EventTarget, for we want to expose an interface to the external.

class MyClass extends EventTarget {
    constructor() {
        super();
        // do stuff
    }
}

We have a custom event type valueChange, and we want it only be dispatched with CustomEvent. So we wrap ValueChangeEvent into a class, and make sure nowhere else we use new CustomEvent("valueChange", {details}).

class ValueChangeEvent extends CustomEvent<string> {
    constructor(detail: string) {
        super("valueChange", { detail });
    }
}

class MyClass extends EventTarget {
    constructor() {
        super();
        // do stuff
    }
}

And now we know e can only be of type ValueChangeEvent, but TypeScript doesn't know that and so it will complain that ValueChangeEvent is not assignable to type Event, for the latter is larger than the former.

const obj = new MyClass();
obj.addEventListener("valueChange", (e: ValueChangeEvent) => {
    // do stuff
})

We currently have some way to solve this.

The first is checking the type of e first. It is troubling to do this in this scenario, but in some stricter situations it might be the best way to go.

obj.addEventListener("valueChange", (e: Event) => {
    if (!(e instanceof ValueChangeEvent)) {
        return;
    }
    // And we can use `e` as a `ValueChangeEvent` fair and square.
});

The second is to reassign an variable and use type assertion to tell TypeScript that we know what we are doing.

obj.addEventListener("valueChange", (e: Event) => {
    const valueChangeEvent = e as ValueChangeEvent;
});

But this is not very elegant, and generates a unnecessary and awkward extra line in the final JavaScript code.

Another way is to use the as keyword each time we need to access detail of the event object. If we assign detail to a variable, we can use it without the as keyword.

obj.addEventListener("valueChange", (e: Event) => {
    const detail = (e as CustomEvent).detail;
});

It is not so troublesome in the CustomEvent example, but if we have more than one extra properties in the type we are sure it would be, we need to assign them to more variables. Nevertheless, we can use destructuring to assign them to variables, so that we still only use as once.

type Type = ...;
type MyType = {
    extra1: string;
    extra2: number;
    extra3: boolean;
    ...
} & Type;
const fnReceivingCallback = (callback: (param: Type) => void) => {
    // internal logic
}
// param is guaranteed to be MyType by the developer
fnReceivingCallback((param: Type) => {
    const {extra1, extra2, extra3} = param as MyType;
})

And the last way is to assert the type of the function. To be honest, it is the worst approach among these four.

obj.addEventListener("valueChange", (e: ValueChangeEvent)) => {
    
} as (e: Event) => boolean);

But personally, I think it is the most elegant that we use type assertions in the parameter list, like this. In this way, TypeScript will know that we have ensured that the parameter is of type ValueChangeEvent.

obj.addEventListener("valueChange", (e as ValueChangeEvent) => {

});
💻 Use Cases
  1. What do you want to use this for?
  2. What shortcomings exist with current approaches?
  3. What workarounds are you using in the meantime?
    All shown in the column above.

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

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

はじめの一歩

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

調査の方向性

issue にはファイル、テスト、またはコンパイラのエントリポイントが名前付きで示されていません。まず、提案されているパラメーターアサーション構文とコールバックの代入可能性との相互作用を調べ、次に、出力される JavaScript を変更せずに例が動作することを示すために必要な型チェックの動作とテストを定義します。

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

評価

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

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

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