microsoft / microsoft/TypeScript

Strange behaviour with assignability and generics

Offen
#36,311 1 Kommentar 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

Needs Investigation
Vorherrschende Sprache
Go
Sterne
111k
Forks
14.3k
Ø Merge
2 T. 4 Std.
Gemergte PRs (30 T.)
132

Beschreibung

TypeScript Version: 3.7.2

Search Terms:

I've read through the related issues and the origin behind this error message, but I still can't wrap my head around this particular case, and it feels like a bug to me. In particular, this feels extra weird because the issue goes away if I just add an extra generic parameter on the interface - even though they are really doing the same thing.

It feels like TypeScript should be able to figure out, that if I pass e.g. Hello1<(a: number) => void> to whoops(), then it should be able to resolve C into (a: number) => void and A into [number]. And if, for some reason, the callee specifies an incompatible set of generics to the functions, that is should fail then, instead of at the function definition.

There are some variations I've tried on the exact signature of the function, but I haven't found anything that works.

Expected behavior: Both examples compile.

Actual behavior: Only one example compiles. The other fails with:

Type 'C' does not satisfy the constraint '(...args: any[]) => void'.
  Type '(...args: A) => void' is not assignable to type '(...args: any[]) => void'.
    Types of parameters 'args' and 'args' are incompatible.
      Type 'any[]' is not assignable to type 'A'.
        'any[]' is assignable to the constraint of type 'A', but 'A' could be instantiated with a different subtype of constraint 'any[]'.

Related Issues: https://github.com/microsoft/TypeScript/issues/29049

Code

// this doesn't work
interface Hello1<C extends (...args: any[]) => void> {
    _1: C
}

function whoops<A extends any[], C extends (...args: A) => void>(
    hello: Hello1<C>
) {}

// this does!
interface Hello2<A extends any[], C extends (...args: A) => void> {
    _1: A
    _2: C
}

function ok<A extends any[], C extends (...args: A) => void>(
    bye: Hello2<A, C>
) { }

Compiler Options
{
  "compilerOptions": {
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "strictPropertyInitialization": true,
    "strictBindCallApply": true,
    "noImplicitThis": true,
    "noImplicitReturns": true,
    "useDefineForClassFields": false,
    "alwaysStrict": true,
    "allowUnreachableCode": false,
    "allowUnusedLabels": false,
    "downlevelIteration": false,
    "noEmitHelpers": false,
    "noLib": false,
    "noStrictGenericChecks": false,
    "noUnusedLocals": false,
    "noUnusedParameters": false,
    "esModuleInterop": true,
    "preserveConstEnums": false,
    "removeComments": false,
    "skipLibCheck": false,
    "checkJs": false,
    "allowJs": false,
    "declaration": true,
    "experimentalDecorators": false,
    "emitDecoratorMetadata": false,
    "target": "ES2017",
    "module": "ESNext"
  }
}

Playground Link: Provided

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 der Reproduktion im TypeScript 3.7.2 Playground und vergleiche die generischen Deklarationen von Hello1 und Hello2; lies anschließend das verwandte Issue #29049, um den Kontext des Fehlers bei der Zuweisbarkeit zu verstehen. Verfolge, warum das erste Beispiel C ablehnt, während das zweite kompiliert; die Aufgabe ist abgeschlossen, wenn geklärt ist, ob beide Beispiele kompilieren sollten, und das geklärte Verhalten durch einen Regressionstest abgedeckt ist.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

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

Neue Issues direkt in Ihr Postfach

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