typescript - Hur filtrerar man och kör med en array av flera typer?


Jag har en array som kan ha två typer A och B. Jag skulle vilja utföra åtgärder på objekt av en typ.

type A = {
  propA: number
}
type B = {
  propB: string
}
type MyArray = Array<A|B>
const anArrayOfBothAAndB: MyArray = [{ propA: 1 }, { propB: '2' }]

anArrayOfBothAAndB.filter((item) => {
  return (item as A).propA
})
.forEach((item: A) => { // reports error here
  console.log(item.propA)
})

Jag kan lägga till kod som const itemA: A=item as any för att få console.log(itemA.propA) att fungera, men det ser inte elegant ut.

Svar #1

Ditt problem är att TypeScript inte är tillräckligt smart för att upptäcka att alla element i arrayen bör vara av typen A efter filtreringen. Du behöver deklarera returtypen för filterfunktionen som item is A. Se dokumentationen här.

Fixad version:

type A = {
  propA: number
}
type B = {
  propB: string
}
type MyArray = Array<A|B>
const anArrayOfBothAAndB: MyArray = [{ propA: 1 }, { propB: '2' }]

anArrayOfBothAAndB.filter((item): item is A => {
  return (item as A).propA !== undefined
})
.forEach((item) => { // no more error, don't even have to specify type
  console.log(item.propA)
})

Svar #2

Tja, sedan 2020 har vissa saker förändrats i TypeScript-världen. filter-metoden kan användas med en generisk parameter. Här är det perfekta exemplet, även med filter-metoden ;)

Givet kodsnutten du har klistrat in här.

type A = {
  propA: number
}
type B = {
  propB: string
}
type MyArray = Array<A|B>
const anArrayOfBothAAndB: MyArray = [{ propA: 1 }, { propB: '2' }]

anArrayOfBothAAndB.filter((item) => {
  return (item as A).propA
})
.forEach((item: A) => { // reports error here
  console.log(item.propA)
})

Det bör finnas en skillnad i det första filter()-anropet, så det bör se ut så här:

anArrayOfBothAAndB.filter<A>((item): item is A => {
    return 'propA' in item;
}).forEach((item) => {
    console.log(item.propA)
})

Skillnaden är att du skickar en predicate-funktion (även kallad type guard) som filter-callback. Så du ger filter denna guard som försäkrar den nya arrayen att det är den typ du predikterar.

Relaterade artiklar