javascript - filter i typescript fikk feilen '(string | null)[]' kan ikke tildeles


Jeg har et array av objekter, en av egenskapene har en null-verdi. Jeg brukte filter for å fjerne den, men TypeScript gir meg en advarsel om at null ikke kan tilordnes. Siden filter aldri vil returnere null, hvorfor gir TypeScript meg en slik feil?

const data = [
  {
    id: "123"
  },
  {
    id: "456"
  },
  {
    id: null
  }
];

const d2: string[] = data.map((d) => d.id).filter((o) => o);

console.log(d2);

demo https://codesandbox.io/s/gallant-water-vio56?file=/src/index.ts:0-165

Svar #1

OPPDATERING SEPTEMBER 2024:

Fra og med TypeScript 5.5 er TypeScript nå i stand til å slutte seg til typepredikater.

Imidlertid vil ikke koden i spørsmålet fortsatt fungere, og grunnen til dette er at funksjonen kan returnere en tom streng. Denne muligheten for en tom streng betyr at det fortsatt er en mulighet for at du har gjort en feil, og derfor beholder TypeScript feilen for å tvinge deg til å se på det.

Du kan enten legge til en eksplisitt returtype (Se det opprinnelige svaret nedenfor), eller du kan endre koden slik at den tomme strengen ikke lenger blir filtrert bort:

const d2: string[] = data.map((d) => d.id).filter((o) => o !== null);

Lekerom lenke


ORIGINELT SVAR:

Typescript kan ikke finne ut at .filter((o) => o) vil innsnevre typene i arrayen, i hvert fall ikke uten litt hjelp. Du kan imidlertid definere en egendefinert typeguard og bruke den. For eksempel:

function notNull<T>(val: T | null): val is T {
    return val !== null;
}

const d2 = data.map((d) => d.id).filter(notNull); // d2 is a string[]

Eller en inline-versjon som bare fungerer med strenger:

const d2 = data.map(d => d.id).filter((o): o is string => !!o);

Lekerom lenke

Svar #2

Å bruke filter vil ikke snevre inn typene for deg. map transformerer dataene til et array av string | null data, og TypeScript vet ikke at d2 ikke vil inneholde null etter filtrering (TypeScript er vel ikke spesielt smart, antar jeg…).

Det finnes et par løsninger — en av dem er komplisert, og den andre er komplisert (selv om ikke så komplisert) sammenlignet med koden din opprinnelig.

Bruk typebeskyttelse

Vi kan eksplisitt bruke typer i filterfunksjonen selv slik at TypeScript vet at resultatet ikke vil inneholde null:

const data = [
  { id: "123" },
  { id: "456" },
  { id: null }
];

// Type guard to filter out null values
const d2: string[] = data.map((d) => d.id).filter((o): o is string => o !== null);

console.log(d2);

Lenke til kode

Kast resultatet etter filtrering

Vi kan også bare kaste resultatet etter at filteret er kjørt i stedet for å tilordne typen på forhånd. Bare legg til as string[] på slutten av linjen din:

const data = [
  {
    id: "123"
  },
  {
    id: "456"
  },
  {
    id: null
  }
];

const d2 = data.map((d) => d.id).filter((o) => o) as string[];

console.log(d2);

Merk: Det vil være en god praksis å inkludere !== null også, slik:

const d2 = data.map((d) => d.id).filter((o) => o !== null) as string[];

Men det er ikke nødvendig, og jeg gikk for enkelhet i den andre løsningen…

Lenke til kode

Relaterte artikler