microsoft / microsoft/TypeScript

Type inference of generics does not work only when callback takes argument

Ouverte
#29,123 3 commentaires 0 réactions 0 personnes assignées Voir sur GitHub

Personne n'a encore pris cette issue.

Bug Domain: check: Type Inference
Langage dominant
Go
Étoiles
111k
Forks
14.3k
Merge moyen
2 j 4 h
PR mergées (30 j)
132

Description

I encountered a strange behavior of type inference about the generic arguments and intersection type. The error described below occurs only when the strictFunctionTypes option is enabled.


TypeScript Version:

Version 3.3.0-dev.20181221

Search Terms:

  • strictFunctionTypes
  • argument intersection type
  • generic argument
  • generic intersection type

Code

tsconfig.json:

{
  "compilerOptions": {
    "moduleResolution": "node",
    "target": "es6",
    "module":"commonjs",
    "strictFunctionTypes": true,
    "outDir": "dist"
  },
  "include": ["*.ts"]
}

source:

const run = <P1, P2>(
  makeProps1: (s: string) => P1,
  makeProps2: () => P2,
  useBoth: (props: P1 & P2) => void
) => {};

const foo = (props: { n: number; b: boolean }) => {};

// This works as expected.
run(() => ({ n: 1 }), () => ({ b: true }), foo);

// But if the first argument function takes a parameter `s`, it results in a compile error.
run(s => ({ n: 1 }), () => ({ b: true }), foo);

Expected behavior:

The type of run is inferred correctly from run(s => ({ n: 1 }), () => ({ b: true }), foo) as below and the code compiles.

const run: <{ n: number; }, { b: boolean; }>(makeProps1: (s: string) => { n: number; }, makeProps2: () => { b: boolean; }, useBoth: (props: { n: number; } & { b: boolean; }) => void) => void

This type is generated from run(() => ({ n: 1 }), () => ({ b: true }), foo). I copied it from Playground's tooltip.

Actual behavior:

It results in the compile error.

output of npx tsc:

repro.ts:9:43 - error TS2345: Argument of type '(props: { n: number; b: boolean; }) => void' is not assignable to parameter of type '(props: { b: boolean; }) => void'.                                  
  Types of parameters 'props' and 'props' are incompatible.
    Property 'n' is missing in type '{ b: boolean; }' but required in type '{ n: number; b: boolean; }'.                                                                                                 

9 run(s => ({ n: 1 }), () => ({ b: true }), foo);
                                            ~~~

  repro.ts:7:23
    7 const foo = (props: { n: number; b: boolean }) => {};
                            ~
    'n' is declared here.


Found 1 error.

This is because the return type of makeProps1 is inferred as {} instead of { n: number; }.

const run: <{}, { b: boolean; }>(makeProps1: (s: string) => {}, makeProps2: () => { b: boolean; }, useBoth: (props: { b: boolean; }) => void) => void

Playground Link:

Here. Note that this problem occurs only when the strictFunctionTypes option is enabled.

Related Issues:

I could not find.

Other Investigation:

In the code below, the type inference works as expected:

const run2 = <P1, P2>(
  makeProps1: (s: string) => P1,
  makeProps2: () => P2,
  useProps1: (p: P1) => void,
  useProps2: (p: P2) => void
) => {};

// The first argument function takes a parameter `s` but it does not change the type inference behavior.
run2(
  s => ({ n: 1 }),
  () => ({ b: true }),
  (p1: { n: number }) => {},
  (p2: { b: boolean }) => {}
);

So it seems that the error only occurs when the generic types (P1, P2) are used as intersection type.

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 l’exemple repro.ts et tsconfig.json, puis exécutez npx tsc avec strictFunctionTypes activé pour confirmer l’échec de l’inférence. Suivez la manière dont les types de retour génériques sont inférés lorsque P1 et P2 sont utilisés comme une intersection, et vérifiez la complétion lorsque le callback prend un argument, sans modifier les types inférés attendus.

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

Évaluation

Stack technique
typescript
Domaine
compilers
Type d'issue
Bug
Difficulté
4/5
Temps estimé
3-5 jours
Activité
À l'abandon
Clarté
Clairement spécifiée
Accessibilité débutants
35/100

Recevez les nouvelles issues par e-mail

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