microsoft / microsoft/TypeScript

Conditional + annotation causes erroneous typing

Offen
#39,409 0 Kommentare 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: 33.9.4 & 4.0.0@beta

Search Terms: Type annotation wrongly overrides generic with errors

Code

const createMatrix = <D extends number, T>(
    dimensions: D,
    initialValues: T | null = null
): Matrix<D, T> => {
    const currentDimensionLength = dimensions;
    const remainingDimensions = dimensions - 1;
    const needsRecursion = remainingDimensions > 0;

    const currentMatrix = Array(currentDimensionLength).fill(initialValues);

    const finalMatrix = needsRecursion
        ? currentMatrix.map(() =>
              createMatrix(remainingDimensions, initialValues)
          )
        : currentMatrix;

    return finalMatrix as Matrix<D, T>;
};
type Matrix<D extends number, T> = D extends 1
    ? T[]
    : D extends 2
    ? T[][]
    : D extends 3
    ? T[][][]
    : any[][][][];

Expected behavior:
Adding type annotations to variables should be compatible with the functions return signature, causing no type errors

Actual behavior:
Assigning an annotated variable to the return value of the function causes an error. The generic T is wrongly inferred to be any of array where depth < D where it should be inferred to only the base type of the nested array. Removing the annotation solves the problem but removes type safety when variable assignment happens after creation.

The problem seems to be that (when annotated) the type is inferred to be the union of each type in Matrix that's preceding the conditional that returns true.

const n1: number[] = createMatrix(1); // <- works - generic T is set to `number`
const n2: number[][] = createMatrix(2); // <- doesn't work - generic T is set to `number | number[]`
const n3: number[][][] = createMatrix(3); // <- doesn't work - generic T is set to `number | number[] | number[][]`

const n4 = createMatrix(2); // <- regular inference works - generic T is `unknown`, return type is unknown[][]
const n5: number[][] = createMatrix(2, 0); // <- works when - initialValues is set - generic T is `number`, return type is number[][]
const n6: unknown[][] = createMatrix(2); // <- works fine, as type T is unknown. A more specific annotation should constrain `unknown` to `number`

Playground Link: Link

Related Issues:
None

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

Verwende die verknüpfte Playground-Reproduktion mit TypeScript 3.9.4 und 4.0.0-beta und konzentriere dich auf die annotierten n2- und n3-Aufrufe im Vergleich zu den nicht annotierten und explizit initialisierten Fällen. Verfolge die Typinferenz und das Verhalten des bedingten Rückgabetyps, bis die Quelle der akkumulierten Union identifiziert ist; abgeschlossen ist die Untersuchung, wenn die annotierten Aufrufe die erwarteten verschachtelten Array-Typen ohne Fehler erzeugen.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
typescript
Bereich
compilers
Issue-Typ
Bug
Schwierigkeit
4/5
Geschätzter Aufwand
3-5 Tage
Aktivitätsstatus
Veraltet
Klarheit
Größtenteils klar
Anfängerfreundlichkeit
35/100

Neue Issues direkt in Ihr Postfach

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