microsoft / microsoft/TypeScript

Function parameters are not inferable when defined via JSDoc using @type tag (with strict)

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

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

Domain: JSDoc Help Wanted Possible Improvement
主要言語
Go
スター
111k
フォーク
14.4k
平均マージ
1日 19時間
マージ済み PR(30日)
117

説明

🔎 Search Terms

infer
@type
strict
JSDoc
Parameters
Function

🕗 Version & Regression Information
  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about type inference.

I've pulled the latest version of this repository and made a test case in the "fourslash" section, which demonstrates the problem I see.
(I couldn't see how to do something like this in the playground, sorry. Commit is linked)

⏯ Playground Link

https://github.com/scottmcginness/TypeScript/commit/cda5366448cb994866517834e0c1ca78b10042cb

💻 Code
// In file func.js
export function func(/** @type {string} */ param) {};
// In file use-it.js
import { func } from "./func.js";
type FuncParam = (typeof func) extends (...args: infer P) => any ? P : never;
//   ^ never, but expected [param: string]

In tsconfig.json:

{
  "compilerOptions": {
    "allowJs": true,
    "checkJs": true,
    "noEmit": true,
    "strict": true
  }
}

(The above definition is obviously just Parameters<T>, but put in full for comparison with another example below)

🙁 Actual behavior

The type FuncParam resolved to never (i.e. it took the false branch of the ternary)

🙂 Expected behavior

The type FuncParam should be [param: string], as given by the JSDoc @type tag

Additional information about the issue

This seems like a bug because all other ways of specifying the func function with JSDoc or the FuncParam type seemed to work as expected:

  • Using the @param tag instead:
/**
 * @param {string} param
 */
export function func(param) {};

yields FuncParam[param: string]

  • Using a union with undefined works, but is not what I want for the definition of func:
export function func(/** @type {string | undefined} */ param) {};

yields FuncParam[param?: string | undefined]

  • Trying the conditional without infer works (but is not usable for the intended purpose):
import { func } from "./func.js";
type FuncIsAFunc = (typeof func) extends (...args: any) => any ? 'good' : never;
//   ^ 'good'
  • Pulling just the first parameter out also works (but obviously that's not how Parameters<T> works):
import { func } from "./func.js";
type FuncParam = (typeof func) extends (arg: infer A) => any ? A : never;
//   ^ string

This also only seemed to occur specifically with strict: true. I couldn't see this with any of the other strict... options (though I may have missed something here)


All other views on the function seems to show that it is happily a function with a string parameter. i.e. the tooltip hover over func, while inside use-it.ts shows:

(alias) function func(param: string): void
import func

The output I see from the single test linked above (using hereby runtests --tests=jsDocInferredFunctionParameters) is:

  1) fourslash tests
       tests/cases/fourslash/jsDocInferredFunctionParameters.ts
         fourslash test jsDocInferredFunctionParameters.ts runs correctly:

      AssertionError: At marker '': quick info text: expected 'type FuncParam = never' to equal 'type FuncParam = [param: string]'
      + expected - actual

      -type FuncParam = never
      +type FuncParam = [param: string]

      at _TestState.verifyQuickInfoString (src\harness\fourslashImpl.ts:1863:16)
      at Verify.quickInfoIs (src\harness\fourslashInterfaceImpl.ts:268:20)
      at eval (jsDocInferredFunctionParameters.js:13:8)
      at runCode (src\harness\fourslashImpl.ts:4618:9)
      at runFourSlashTestContent (src\harness\fourslashImpl.ts:4576:5)
      at runFourSlashTest (src\harness\fourslashImpl.ts:4559:5)
      at Context.<anonymous> (src\testRunner\fourslashRunner.ts:59:39)
      at processImmediate (node:internal/timers:476:21)

This also happens for arrow functions and class methods, e.g.

// In func.js
export const func = (/** @type {string} */ param) => {};
export class Cls{
  method(/** @type {string} */ param) {}
}

with similar code as for FuncParam.

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

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

はじめの一歩

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

調査の方向性

tests/cases/fourslash/jsDocInferredFunctionParameters.ts から始め、issue に記載された hereby コマンドで実行して quick-info の失敗を再現します。strict mode で JSDoc @type によって注釈付けされた JavaScript パラメーターについて、arrow functions と class methods を含め、TypeScript checker の動作を追跡します。推論されたパラメーターのタプルについて、テストが never ではなく [param: string] を報告すれば完了です。

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

評価

技術スタック
javascript, typescript
領域
compilers
issue の種類
バグ
難易度
4/5
見積もり時間
3〜5日
活発さ
停滞
明瞭さ
明確に書かれている
初心者へのやさしさ
38/100

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

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