microsoft / microsoft/TypeScript

Error on function return is less useful than it should be

Ouverte
#63,357 1 commentaire 0 réactions 0 personnes assignées Voir sur GitHub

Personne n'a encore pris cette issue.

Domain: check: Contextual Types Possible Improvement
Langage dominant
Go
Étoiles
111k
Forks
14.3k
Merge moyen
2 j 4 h
PR mergées (30 j)
132

Description

### 🔍 Search Terms

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

### ✅ Viability Checklist

- [x] This wouldn't be a breaking change in existing TypeScript/JavaScript code
- [x] This wouldn't change the runtime behavior of existing JavaScript code
- [x] This could be implemented without emitting different JS based on the types of the expressions
- [x] This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
- [x] This isn't a request to add a new utility type: https://github.com/microsoft/TypeScript/wiki/No-New-Utility-Types
- [x] This feature would agree with the rest of our Design Goals: https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals

### ⭐ Suggestion

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

```ts
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(arg: NoInfer): 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:

```ts
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](https://www.typescriptlang.org/play/?ts=6.0.2#code/C4TwDgpgBAShxQLxQN4EMBcUB2BXAtgEYQBOAvgNwBQokUAYtklABQCUSAfLPNVQMYB7bAGcEASxEjcELI2bsuqKgHoVUDVAB6UcQhEALQQHcRUYAeikSgklEslZUACrhoAckWJuKKJihiJOLYAOYUUGTuumbYgghoUuIh2GiEADbQwILmblCeHN6oflh4RKThkQB0VJpQjsC4JEzoWABEAEwArK2Uquq1AzrBYhBoACZQggBm9qQQVL19fmNjwSF+TBAAHmBp4vx6dfCNTLTQU+JbEGZ6AsJiUMa2ANZoNrjYYwCMckzI7Fg4AhCigapp6idUP4Ot1emoBoMAkZTLNHFhXHR3IE1lFJDg4n5EslUhlzNkznlSsQSO5qot4RCmmtHnojLh4lB0oJ+M9OYIxiAoBcrjdgHdRAgniRXu9Pu1fgoCtwWC0oDCemxqPCETrdbqdIYTGYHE4MR5saFcTECQkREkUulMuTcu4qaRaVRxQ9CI40M81gr-krlLVGc1-F0ADScrCdABscP6eoROjAjgAbuJBLgRGkQNGLHNHtm0hNiPioNZbKiINVtcmdcZWeYDHj+AY0KEnAB5QgAKwg-AQe2ApDQaSg+DQguEeYCkAOU0Fz1ixiYacEkBIwHE12jnYm7kIUTGgmu+IQ20kElOLt8-jdJAqHsoQA)

### 📃 Motivating Example

```ts
interface App {
start: () => {
title: {
name: string,
},
},
}

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

[Playground link](https://www.typescriptlang.org/play/?ts=6.0.2#code/JYOwLgpgTgZghgYwgAgIIAd3IN4ChkHIDOYcUYAXMgBQCUyAvAHw76HtjBgA2EVe7QYRBwAtn2JgooAOYAaNkIC+C9itxLcuCAA90Ae3LIE+kCWRxMVDFgat2JMpRr1m9ocigQwAVygh3D0JOHgkBII8RcSoAJgBWVQiCdSClAG5FZHV0oA)

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.

Guide de contribution

Ouvrir le guide de contribution

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Piste de recherche

Commencez par les deux exemples de Playground afin de reproduire les diagnostics actuels et de comparer les emplacements et les messages signalés. Étudiez la manière dont les types de retour contextuels sont gérés pour les fonctions dont le corps est un bloc, puis vérifiez que les erreurs sont déplacées vers l’expression de retour en cause sans modifier le comportement documenté des propriétés en excès.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Évaluation

Stack technique
typescript
Domaine
compilers
Type d'issue
Fonctionnalité
Difficulté
5/5
Temps estimé
Plus d'une semaine
Activité
Calme
Clarté
Plutôt claire
Accessibilité débutants
45/100

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.