typescript - TS2339: Ayırt edici birleşimde Array.find türünü doğru şekilde çıkarmıyor
Bu örnekte, farklı türde öğelerle doldurulabilecek bir arabam var; bu durumda bunlar golf topları ve golf sopalarıdır ve bunların kendi seçenekleri vardır.
Typescript Playground bağlantısı
Aşağıdaki kod ile şu hatayı alıyorum:
TS2339: Property 'color' does not exist on type '{ color: "blue" | "red" | "white"; } | { variant: "wedge" | "putter"; }'.
Property 'color' does not exist on type '{ variant: "wedge" | "putter"; }'.
type ProductGolfBall = {
type: "golfball";
options: {
color: "blue" | "red" | "white";
};
};
type ProductGolfClub = {
type: "golfclub";
options: {
variant: "wedge" | "putter";
};
};
type CartItem = ProductGolfBall | ProductGolfClub;
type CartItems = Array<CartItem>;
const cart: CartItems = [
{
type: "golfball",
options: {
color: "blue"
}
},
{
type: "golfclub",
options: {
variant: "wedge"
}
},
{
type: "golfclub",
options: {
variant: "putter"
}
}
];
const golfball = cart.find((item) => item.type === "golfball");
if (golfball) { // Check that it's truthy
// According to typescript this can still be either ProductGolfClub or ProductGolfBall
console.log(golfball.type)
console.log(golfball.options.color) // Produces the TS2339 error above
}
Şimdi sadece, `find` işlemi yalnızca `type` özelliği `golfball` olan bir dizi öğesi için true döndürürken neden `golfball` değişkeninin hala `ProductGolfClub` olabileceğini anlamıyorum.
golfball değişkenini ProductGolfBall olarak dönüştürebilirdim, ama typescript'in değişkenin hangi tipe sahip olduğunu anlaması için başka bir yol olmalı.
Cevap #1
Ne yazık ki TS bu durumdan kutudan çıktığı gibi tür koruyucu oluşturamıyor. Ama işlevin neyi garanti edeceğini açıkça belirterek elle yapabilirsiniz, şöyle düşünün:
function isGolfBall(item: CartItem): item is ProductGolfBall {
return item.type === "golfball";
}
const golfball = cart.find(isGolfBall)
if (golfball) { // Check that it's truthy
console.log(golfball.type)
console.log(golfball.options.color) // no error 👌
}
En önemlisi :item is ProductGolfBall. Bu, bu fonksiyonun açıkça bir tür koruyucu olacağını ve yalnızca ProductGolfBall için geçeceğini (true döndüreceğini) ifade eder.
Satır içi çözüm de olur:
const golfball = cart.find((item): item is ProductGolfBall => item.type === "golfball")
