microsoft / microsoft/TypeScript

Omitted arguments are not candidates for possibly-undefined type parameters

Offen
#61,069 0 Kommentare 0 Reaktionen 1 zugewiesene Person Auf GitHub ansehen

@gabritto arbeitet bereits daran.

Seit 31.1.2025.

Domain: check: Type Inference Possible Improvement
Vorherrschende Sprache
Go
Sterne
111k
Forks
14.3k
Ø Merge
2 T. 4 Std.
Gemergte PRs (30 T.)
132

Beschreibung

Background

Playground Link

Consider the following code that is trying to leverage #56941.

type QuickPickReturn<Multiple extends boolean | undefined> =
    Multiple extends true ? string[] :
    Multiple extends false | undefined ? string :
    never;

/**
 * @param prompt The text to show to a user.
 * @param items Whether a user can select multiple options, or just a single option.
 * @param canSelectMultiple Each of the options presented to the user.
 **/
function showQuickPick<Multiple extends boolean | undefined>(
    prompt: string,
    items: readonly string[],
    canSelectMultiple?: Multiple,
): QuickPickReturn<Multiple> {
    let buttons = items.map((item, index) => ({
        selected: index === 0,
        text: item,
    }));

    // other code goes code here...

    if (canSelectMultiple) {
        return buttons
            .filter(button => button.selected)
            .map(button => button.text);
    }
    return buttons.find(button => button.selected)!.text;
}

This code has an optional parameter canSelectMultiple. Because it is optional, the Multiple type parameters cannot simply be constrained to boolean - they must factor in undefined for various narrowing and assignability checks to work out.

Most calls work as expected.

// `true` gives a `string[]` - works ✅
let shoppingList: string[] = showQuickPick(
    "Which fruits do you want to purchase?",
    ["apples", "oranges", "bananas", "durian"],
    true,
);

// `false` - works ✅
let dinner: string = showQuickPick(
    "What's for dinner tonight?",
    ["sushi", "pasta", "tacos", "ugh I'm too hungry to think, whatever you want"],
    false,
);

undefined explicitly also works

// `undefined` gives a `string` - works ✅
let dinner2: string = showQuickPick(
    "What's for dinner tonight?",
    ["sushi", "pasta", "tacos", "ugh I'm too hungry to think, whatever you want"],
    undefined,
);

However, if we omit the argument, we assume that there are no candidates for inference available and fall back to the constraint boolean | undefined. This changes our output type to string | string[], which is an error in the following code:

// Omitted argument gives a `string | string[]` - ❌
let dinner3: string = showQuickPick(
    "What's for dinner tonight?",
    ["sushi", "pasta", "tacos", "ugh I'm too hungry to think, whatever you want"],
);

Proposal

When TypeScript infers type arguments to type parameters based on actual call arguments, we walk through parameters with missing corresponding arguments and infer from the type undefined to each parameter's type.

Some things to consider if we discuss this:

  • How would this function with missing properties? Do we need to do something similar there?
  • Is it always desirable to do this inference? Do we need a different inference priority?
  • This behavior is correct for purely-optional parameters, but is it correct for parameters with default arguments? (I realized this hairball of a problem after posting this issue)

Beitragsleitfaden

Beitragsleitfaden öffnen

Erste Schritte

  1. Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
  3. Forke das Repository und arbeite in einem Branch.
  4. Öffne einen Pull Request, der die Issue-Nummer nennt.

Bewertung

Dieses Issue wurde noch nicht bewertet.

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.