Home > Back-end >  Typeguarding an unknown nested object
Typeguarding an unknown nested object

Time:10-08

I want to create a type guard for an error that I know is a nested object like this:

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

The error, if it exists will initially be determined as an unknown type by the library returning the error. I want to create a custom type guard that checks the error and converts its type to something more appropriate.

Here's what I've tried so far:

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)
}

This results in an error from the typescript compiler prompting that:

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

What's the correct way to type guard this kind of an unknown nested object?

CodePudding user response:

TS 4.9

TypeScript 4.9 offers better narrowing with in, as you can read in their announcements here.

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

Playground (using 4.9)

Same playground with 4.8


TS 4.8-

Unfortunately there is no easy way around it. You should just do a cast, even if it's ugly:

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

Maybe even using any instead of unknown as the parameter type:

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