microsoft / microsoft/TypeScript

Error on function return is less useful than it should be

Offen
#63,357 1 Kommentar 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

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

Beschreibung

🔍 Search Terms

"contextual typing of function return values" "function return error in the wrong place"

✅ Viability Checklist
⭐ Suggestion

Often when writing a function where the return type should be known, errors appear overly complicated and far away from their source.

type Ret = {a: number};
type Fn = () => Ret;


const issue: Fn = () => {
//    ^ it shows the error here: Type '() => { a: string; }' is not assignable to type '() => { a: number; }'.
    return {a: "25"};
//          ^ instead of here
};


// adding an explicit return type fixes it
const workaround1: Fn = (): Ret => {
    return {a: "25"};
//          ^ shows here: Type 'string' is not assignable to type 'number'.
};


// returning without a block body fixes it
const workaround2: Fn = () => ({a: "25"});
//                              ^ shows here: Type 'string' is not assignable to type 'number'.


// using a helper function fixes it
function inferRet<T>(arg: NoInfer<T>): T {
    return arg;
}
const workaround3: Fn = () => {
    return inferRet({a: "25"});
//                   ^ shows here: Type 'string' is not assignable to type 'number'.
};

Unfortunately, this would be a breaking change as it would cause some existing working code to now error, so it would have to be added under a compiler flag or wait for 7.0/8.0:

const breaking: Fn = () => {
    return {a: 25, b: 56};
//                 ^ previously, there would be no error here.
//                   with this change: Object literal may only specify known properties, and 'b' does not exist in type '{ a: number; }'.
};

Playground link

📃 Motivating Example
interface App {
    start: () => {
        title: {
            name: string,
        },
    },
}

export const app: App = {
    start: () => {
        return {
            title: {
                name: 25,
            },
        };
    },
};

Playground link

Previously, the error would show as:

10 |     start: () => {
         ~~~~~
Type '() => { title: { name: number; }; }' is not assignable to type '() => { title: { name: string; }; }'.
  Call signature return types '{ title: { name: number; }; }' and '{ title: { name: string; }; }' are incompatible.
    The types of 'title.name' are incompatible between these types.
      Type 'number' is not assignable to type 'string'.(2322)
input.tsx(2, 5): The expected type comes from property 'start' which is declared here on type 'App'

With this change, the error will show as:

13 |                name: 25,
                    ~~~~
Type 'number' is not assignable to type 'string'.(2322)
input.tsx(2, 5): The expected type comes from property 'name' which is declared here on type '{ name: string; }'

The second one is clearly easier to read and fix

💻 Use Cases
  1. What do you want to use this for?
    Interfaces that define functions with return types
  2. What shortcomings exist with current approaches?
    workaround 1: Explicitly setting the return type is annoying, and shouldn't need to be done when typescript clearly knows what it should be.
    workaround 2: Not using a block body is often not reasonable when computation needs to be done in the body of the function.
    workaround 3: You shouldn't need to define a helper function for this
  3. What workarounds are you using in the meantime?
    Every time I define a function where the return type could be inferred, I always specify it manually to make the errors easier to read.

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.

Rechercherichtung

Beginne mit den beiden Playground-Beispielen, um die aktuellen Diagnosen zu reproduzieren und die gemeldeten Positionen und Meldungen zu vergleichen. Untersuche, wie kontextabhängige Rückgabetypen für Funktionen mit Blockkörper behandelt werden, und verifiziere anschließend, dass die Fehler auf den fehlerhaften Rückgabeausdruck verschoben werden, ohne das dokumentierte Verhalten bei überschüssigen Eigenschaften zu ändern.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
typescript
Bereich
compilers
Issue-Typ
Feature
Schwierigkeit
5/5
Geschätzter Aufwand
Über eine Woche
Aktivitätsstatus
Ruhig
Klarheit
Größtenteils klar
Anfängerfreundlichkeit
45/100

Neue Issues direkt in Ihr Postfach

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