microsoft / microsoft/TypeScript

Conditional + annotation causes erroneous typing

Aperta
#39,409 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

Needs Investigation
Lingua principale
Go
Stelle
111k
Fork
14.3k
Merge medio
2g 4h
PR unite (30g)
132

Descrizione

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

Guida per i contributori

Apri la guida per i contributori

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Direzione di ricerca

Usa la riproduzione collegata di Playground con TypeScript 3.9.4 e 4.0.0-beta, concentrandoti sulle chiamate n2 e n3 annotate rispetto ai casi non annotati e inizializzati esplicitamente. Traccia l’inferenza dei tipi e il comportamento del tipo di ritorno condizionale fino a identificare l’origine dell’unione accumulata; il lavoro è concluso quando le chiamate annotate producono i tipi di array annidati previsti senza errori.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Valutazione

Stack tecnologico
typescript
Ambito
compilers
Tipo di issue
Bug
Difficoltà
4/5
Tempo stimato
3-5 giorni
Stato di attività
Ferma
Chiarezza
Abbastanza chiara
Idoneità per principianti
35/100

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.