javascript - Typkontroll av ett okänt nästlat objekt


Jag vill skapa en typvakt för ett fel som jag vet är ett nästlat objekt som detta:

const myError = {
   status: 404,
   data: {
        foo: "bar"
       }
}

Felet, om det existerar, kommer initialt att bestämmas som en okänd typ av biblioteket som returnerar felet. Jag vill skapa en egen typvakt som kontrollerar felet och konverterar dess typ till något mer lämpligt.

Här är vad jag har provat hittills:

type MyError = {
    status: number,
    data: {
        foo: string
        }
}

const myErrorTypeguard = (myError: unknown): myError is MyError => {
    return (typeof myError === 'object'
    && myError !== null
    && 'status' in myError
    && 'data' in myError
    && 'foo' in myError.data)
}

Detta resulterar i ett fel från TypeScript-kompilatorn som påpekar att:

Property 'data' does not exist on type 'object'.

Vad är det rätta sättet att skriva en typkontroll för den här typen av okänt nästlat objekt?

Svar #1

TS 4.9+

TypeScript 4.9 erbjuder bättre avgränsning med in, som du kan läsa i deras tillkännagivanden här.

return (typeof myError === 'object'
    && myError !== null
    && 'status' in myError
    && 'data' in myError // myError is now of type object & Record<"data", unknown>
    // the icky part: TypeScript requires us to do this... which is understandable
    && typeof myError.data === "object" && myError.data !== null
    && 'foo' in myError.data) // so now this works

Lekplats (använder 4.9)

Samma lekplats med 4,8


TS 4.8-

Tyvärr finns det inget enkelt sätt runt det. Du bör bara göra ett gjut, även om det är fult:

return (typeof myError === 'object'
    && myError !== null
    && 'status' in myError
    && 'data' in myError
    && 'foo' in (myError as any).data) // or myError as { data: {} }...?

Kanske till och med använda any istället för unknown som parametertyp:

const myErrorTypeguard = (myError: any): myError is MyError => {
//                        ~~~~~~~  ^^^