Typescript Typeguard kontrollera om arrayen är av typen
Jag vill skriva en typvakt för att kontrollera om alla barn i en array är av typen T och på så sätt göra det till en Array där T är en generisk typ
TS Lekplats
// Assume arr of any type but Array
const arr: any[] = [
{
foo: "bleh1",
bar: 1
},
{
foo: "bleh2",
bar: 2
},
]
interface newType {
foo: string
bar: number
}
// Check that arr is an array of newType , ie arr: newType[]
const isArrayOf = <T,>(arr: any): arr is Array<T> => {
// TypeScript mastery needed here
return true
}
if(isArrayOf<newType>(arr)){
arr
}
Svar #1
Det bästa du kan göra är detta:
const arr: NewType[] = [
{
foo: "bleh1",
bar: 1
},
{
foo: "bleh2",
bar: 2
},
]
interface NewType {
foo: string
bar: number
}
type TypeOfArrayElements<T> = T extends Array<infer U> ? U : never;
type ArrayType = TypeOfArrayElements<typeof arr>;
TypeScript kommer aldrig kunna gissa att arrayen typad som any[] faktiskt innehåller NewType-element. Som allt i TypeScript är typförutsättningar statiska och kommer inte att returnera en typ dynamiskt baserat på vad som skickas som parameter vid körning. Men om du typar den som NewType[] kan du då extrahera NewType-typen från den.
Svar #2
Redigera 1:
Detta svar har två brister (nämnda i kommentarer)
- Egenskapen behöver inte vara egen för att den ska existera på objektet
x={a: 1}; y=Object.create(x); y.b=2 - Funktionen kräver att du manuellt uppräknar alla nycklar i objektet. Detta kan därför introducera mänskliga fel
Jag tror att lösningen fortfarande kan användas som en tillfällig lösning i specifika omständigheter
Original :
Om en array a är av typen newType[] så kommer varje element i a, till exempel x=a[0], att vara av typen newType. x är av typen newType eftersom x uppfyller alla egenskaper och metoder för typen newType.
Så om det omvändes, om x y z är av typen newType och de är de enda och alla element i arrayen a, så är varje element i a av typen newType, vilket uppfyller villkoret för att a ska vara av typen newType[]
// Check if obj has all keys props[]
const hasAllProperties = <T,>(obj: any, props: (keyof T)[]): obj is T => {
return props.every((prop) => {
// console.log(prop)
return Object.prototype.hasOwnProperty.call(obj, prop)})
}
// Check that arr is an array of newType , ie arr: newType[]
const isArrayOf = <T,>(obj: any[], props: (keyof T)[]): obj is T[] => {
// Check if every elements have all keys in props
return obj.every((ele) => {
// console.log(ele)
return hasAllProperties<T>(ele,props)
}
)
}
if (isArrayOf<newType>(arr, ["foo", "bar"])) {
console.log("arr is of newType[]")
}
TS Lekplats
