So in part 1 of this series, we looked at how the typeof
operator can be used to infer the Typescript type of an object. There’s a bunch more ways to infer types, and it makes working with Typescript pretty interesting as you can make the type inference do the work for you. Here’s a few of them:
Infer the ReturnType of a function
Works like you’d expect:
> function isEmpty(s: string | null | undefined) { return s === "" || s === null || s === undefined }
> let a: ReturnType<typeof isEmpty>
> a = "hello"
[eval].ts:3:1 - error TS2322: Type '"hello"' is not assignable to type 'boolean'.
3 a = "hello"
~
undef
Note the slightly weird construction: ReturnType <typeof isEmpty>
. That’s because ReturnType (just like all Typescript types) expects a type as a parameter, and not a value.
Infer the type of an instance from the Class Name
Just like ReturnType
, there’s also InstanceType
:
> class Trigger { x = 0; y = 0 }
> let g: InstanceType<typeof Trigger> = "hello"
[eval].ts:14:5 - error TS2322: Type '"hello"' is not assignable to type 'Trigger'.
Infer the type of Props of a React Component
Here’s a code fragment from Reactist test suite that illustrates this:
const getAvatar = (
props?: Omit<React.ComponentProps<typeof Avatar>, 'user'> & {
user?: { name?: string; email: string }
}
) => (
<Avatar
user={{ name: 'Henning Mus', email: 'henning@doist.com' }}
size="xl"
{...props}
/>
)
As you can see React.ComponentProps
works pretty much like ReturnType
, so you don’t really need to export Props from a component ever. (h/t Janusz)
Typescript has far more complex inference (the infer keyword comes to mind), but this is good enough to start and really simplifies a lot of use-cases, and avoids unneeded type exports from a library.
Leave a Reply