microsoft / microsoft/TypeScript

Evolving any behavior for local function variables

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

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

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

説明

Search Terms

  • evolving callback

Suggestion

When you declare a local variable whose type is implicitly any, it has an opportunity to "evolve" before triggering an implicit any error:

let x = null;  // type is any, but not an error
if (Math.random() < 0.5) x = 'hello';
x;  // type is string | null

My suggestion is to allow a similar behavior for functions whose parameters implicitly have an any type. This is currently an error, but there's nothing wrong with the code:

{
  const mapFn = x => x * x;
  // Parameter 'x' implicitly has an 'any' type. (7006)
  [1, 2, 3].map(mapFn);
}

If x's type were allowed to "evolve" from any to number, this correct code would type check.

Anders doesn't like "spooky action at a distance." But perhaps some limited, self-contained action within a block could solve this problem while avoiding the spookiness?

Use Cases

The loss of contextual types when you factor out a variable is a perennial pain point in TypeScript. See, for example:

This is felt most acutely with React components, where factoring out a function often forces you to dig through type declarations for fairly complicated event types. See below.

Examples

The Array.prototype.map example above is one.

Here's an example with a React component. An inline handler requires no explicit types:

function LoggedCell(props: {cellText: string}) {
  return (
    <td onClick={e => {
        e.stopPropagation();
        // do something
      }}>{props.cellText}</td>
  );
}

Factoring out the callback into a local variable produces a no implicit any error:

function LoggedCell(props: {cellText: string}) {
  const clickFn = e => {
    // Parameter 'e' implicitly has an 'any' type.ts(7006)
    e.stopPropagation();
    // .. do something ...
  };

  return (
    <td onClick={clickFn}>{props.cellText}</td>
  );
}

You can dig up the parameter type to fix this, but it's a mouthful:

function MyComponent() {
  const clickFn = (e: React.SyntheticEvent<HTMLTableDataCellElement>) => {
    e.stopPropagation();
    // .. do something ...
  };

  return (<td onClick={clickFn}>Table Cell</td>);
}

There's nothing really wrong with the middle version. I think it should work.

Caveats:

  • Would this mean the type checker has to go back and type check the function body? Is that possible? Would that break lots of other things?

  • If you used the callback in two places, would its type have to be the union of the two? Evolving any has this behavior, e.g. if you push a number and a string onto an array, its type becomes (number|string)[].

  • Is it OK to return the function? Or let its inferred type "escape" in some other way?

  • Like the current evolving any, this probably wouldn't work in functions (#35132). So you couldn't use it in a React component that calls map, for example:

    contents.map(cell => <td onClick={clickFn}>{cell}</td>);
    

Checklist

My suggestion meets these guidelines:

  • This wouldn't be a breaking change in existing TypeScript/JavaScript code

This would allow some code that triggers a type error now to pass. Not sure if that's what's meant by "breaking." The code that passes would be code that works correctly at runtime.

  • 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 番号を参照したプルリクエストを送ります。

調査の方向性

実装ファイル、テスト、エントリーポイントは示されていません。まず、noImplicitAny を有効にしてローカルのコールバック例を再現し、issue に記載されている既存の evolving-any の挙動を読みます。推論とエスケープの規則について合意し、受け入れられるケースと拒否されるケースを type-checker のテストで網羅できれば完了です。

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

評価

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

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

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