Microsoft/TypeScript

Type inference lost after spreading array with `ArrayLike`

Open

#58 286 ouverte le 22 avr. 2024

Voir sur GitHub
 (2 commentaires) (1 réaction) (0 assignés)TypeScript (6 726 forks)batch import
Domain: check: Type InferenceHelp WantedPossible Improvement

Métriques du dépôt

Stars
 (48 455 stars)
Métriques de merge PR
 (Merge moyen 6j 17h) (9 PRs mergées en 30 j)

Description

🔎 Search Terms

array inference, type inference, ArrayLike, lodash compact, _.compact

🕗 Version & Regression Information

  • This changed between versions 4.9.5 and 5.0.4

⏯ Playground Link

https://www.typescriptlang.org/play?ts=5.0.4#code/C4TwDgpgBAsiAq4IB55QgD2BAdgEwGcoBXHAaxwHsB3HAPigF4oBvAKCigFsQBpCEAC4o8ANwduIAGKkAxsACWlHMIAUAQwBOAcwCMw+AEomDAG6UFecQF9xbWcoLAo23BE3rsTKKsPCAgpoeIMhwiJDITpoKONp0DIwM7JyaEMDEmjhQgcEAdABmmpRcqixQADa42sAAFsIArFDWhrlc6mChCEiRwNGx8aqqAPoANFAxeJjGiawSKWkZWcmcKzz8QlAABgAkLBOY1psjc6vScorKalp600knK1Cp6ZniD5zWxw+2Es02dg44JxQLTBAAyCjIEAAkjh8u5cLIIDIcPIlFlmKh0FhcIQSOQqLQ6KoJCCAkF1CBwZDMQAfKA4YjlcpQOmkSb5GIQPAsqD5dTlAjQOkAImFPIADAw6QymTy2RAOTguWw-CIANoAXRMs3mzyymr+bHsjmcIIpVOhsPcqRR0GYZspEMtcJtiORqOUqjVEjKawEwmFugATABmYVjHjui4qHymfnECC3VjWJqfKC9BNQABkWdYknWAYALPUAGzhyRRtFqOPlBNJlgpj4SPkC6A5vN+jbC4tliNnFHR6vxxPahupiS5SeuJUebC+NMAegX6aQ4ytQQgiKglHyFfOaPGRHKlCcEgzbdzvr4-qg3dL5cj+8useH9cbaZbguzl-zN7vvb3AcqxfWsRxmMcm04K8C1vHsH37D0Y1UGs61Hd82A1Qx-hNYFyRAGEXQRJEn3RKBMUwbB8CIUgKBoehiU4Ulsjw2l6UZZlWXwBVOW5OlPyFW8xTpSUeRlDi8XZHiVQMTVRwkJ5FigA02G+Y1AVNPCCPhW1vAdLTXWIoDPW9KDfy7YMwz7Stn2Q180PHThz2-Dtry7OCrJIodQLfBzeX5L922gv93MAxCvNQ8D0M4SdcmndxPAgecJCXFdIDXF1Ui3HdQujQ8oEhMBgDPTRM0Csyi3vDyjKQlCwKSKK-NbZygrcyqcuA2zvPsyCXJg-94Osmq7Mi8dMPEIA

💻 Code

type MyType<T extends unknown> = {
  myKey: T;
  myFunction: (arg1: T) => void;
};

const generate = (): Array<MyType<string>> => {
  return Array.from({ length: 5 }).map<MyType<string>>((_, index) => {
    return {
      myKey: `${index}`,
      myFunction: (arg1) => {
        return;
      },
    };
  });
};

const arrayLikeInferenceFunction = <T extends unknown>(
  arr: ArrayLike<T | null | undefined | false | "" | 0> | null | undefined
): T[] => {
  return [];
};

const arrayLikeInference = arrayLikeInferenceFunction([
  { myKey: "123", myFunction: (value) => {} }, // value is correctly inferred as string
  true && { myKey: "456", myFunction: (value) => {} },
  false && { myKey: "456", myFunction: (value) => {} },
  ...generate(),
  // type inference of myFunction is lost
  true && { myKey: "456", myFunction: (value) => {} }, // value is inferred as any
  false && { myKey: "456", myFunction: (value) => {} },
  { myKey: "456", myFunction: (value) => {} },
]);

const arrayInferenceFunction = <T extends unknown>(
  arr: Array<T | null | undefined | false | "" | 0> | null | undefined
): T[] => {
  return [];
};

const arrayInference = arrayInferenceFunction([
  { myKey: "123", myFunction: (value) => {} }, // value is correctly inferred as string
  true && { myKey: "456", myFunction: (value) => {} },
  false && { myKey: "456", myFunction: (value) => {} },
  ...generate(),
  // type inference of myFunction is kept
  true && { myKey: "456", myFunction: (value) => {} }, // value is correctly inferred as string
  false && { myKey: "456", myFunction: (value) => {} },
  { myKey: "456", myFunction: (value) => {} },
]);

🙁 Actual behavior

The typings of the arguments of myFunction are lost after the array spread when using ArrayLike. When using Array, the type inference is kept.

🙂 Expected behavior

The arguments of myFunction should be inferred as string

Additional information about the issue

I have opened a similar issue in the DefinitelyTyped repository for the lodash typings and they suggested opening an issue in this repository. https://github.com/DefinitelyTyped/DefinitelyTyped/discussions/69410

The issue originated from using lodash.compact() with code similar to the code below:

import _ from "lodash";

type MyType<T extends unknown> = {
  myKey: T;
  myFunction: (arg1: T) => void;
};

const generate = (): Array<MyType<string>> => {
  return Array.from({ length: 5 }).map<MyType<string>>((_, index) => {
    return {
      myKey: `${index}`,
      myFunction: (arg1) => {
        return;
      },
    };
  });
};

const lodashInferred = _.compact([
  { myKey: "123", myFunction: (value) => {} }, // infers value as string
  true && { myKey: "456", myFunction: (value) => {} },
  false && { myKey: "456", myFunction: (value) => {} },
  ...generate(),
  { myKey: "123", myFunction: (value) => {} },  // infers value as any
  true && { myKey: "456", myFunction: (value) => {} },
  false && { myKey: "456", myFunction: (value) => {} },
]);

Guide contributeur