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
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 => {
// ~~~~~~~ ^^^