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.
