Skip to content

Rule proposal: promise aggregator method checks #11694

@valadaptive

Description

@valadaptive

Before You File a Proposal Please Confirm You Have Done The Following...

My proposal is suitable for this project

  • My proposal specifically checks TypeScript syntax, or it proposes a check that requires type information to be accurate.
  • My proposal is not a "formatting rule"; meaning it does not just enforce how code is formatted (whitespace, brace placement, etc).
  • I believe my proposal would be useful to the broader TypeScript community (meaning it is not a niche proposal).

Description

I debated whether I should report this as a bug in the await-thenable rule or as a proposal to move the behavior into a new rule.

The behavior in question is around the await-thenable rule's new functionality, where it will report an error if you pass an array of Promise<T> | (some non-promise type) into a promise aggregator method like Promise.all.

This was reported as a bug in #11609, since it rejects valid and useful code. That bug was "fixed" in #11611, but specifically only for the case of array literals. The following code is still rejected:

declare const mixedPromises: (Promise<number> | null)[];

Promise.all(mixedPromises);

I must admit I don't understand the logic behind #11611, or why exactly array literals are so special. However, this behavior seems to be deliberate, so I'm opening this as a feature request instead of a bug report.

I believe the "promise aggregator method must take all Promises" check should never have been made part of await-thenable, because:

  1. It has nothing to do with the await keyword, and doesn't even require the await keyword to be used in order to trigger. The documentation for await-thenable only mentions the await keyword, and doesn't mention promise aggregator methods anywhere.
  2. It cannot be independently configured or disabled.
  3. The await-thenable rule permits awaiting unions of promises and non-promises:
    declare const mixedPromise: Promise<number> | null;
    async function foo() {
      // This is fine!
      await mixedPromise;
    }

I think that check should therefore be moved into a new rule. This new rule should allow unions of promises and non-promises by default, whether or not they're passed in as an array literal, and the stricter behavior should be an opt-in option (since it rejects code with valid use cases). I don't see any benefit to differentiating between array variables and array literals here--could @ronami perhaps fill me in on why they're treated differently right now?

Fail Cases

declare const nonPromises: number[];
Promise.all(nonPromises);

// With the "stricter" option enabled:
declare const mixedPromises: (Promise<number> | number)[];
Promise.all(mixedPromises);

Pass Cases

// With the "stricter" option *disabled*:
declare const mixedPromises: (Promise<number> | number)[];
Promise.all(mixedPromises);

declare const allPromises: Promise<number>[];
Promise.all(allPromises);

Additional Info

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancement: new plugin ruleNew rule request for eslint-pluginpackage: eslint-pluginIssues related to @typescript-eslint/eslint-plugintriageWaiting for team members to take a look

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions