typescript: inferring types

2021-12-20

 | 

~2 min read

 | 

367 words

Let’s assume I have a type that’s defined in a third party library. Let’s say its shape is:

type Foo = {
  id: string
  results: Array<{ bar: string }>
}

How might I be able to derive the type of the array (i.e., { bar: string })?

I asked on StackOverflow and got two interesting solutions:

  1. Leverage the fact that arrays are indexed by integers
  2. Create a new utility type ElementsOf

Array Indexes

The first solution takes advantage of the fact that an array is indexed by integers. Because of this, we can get Typescript to infer the type of our key like so:

type Baz = Foo["results"][number]

Now, variables of type Baz will infer the type from Foo:

const baz: Baz = { bar: "any string" }
const bazFail1: Baz = { bam: "unknown key" } // will fail as "Type '{ bam: string; }' is not assignable to type '{ bar: string; }'."
const bazFail2: Baz = { bar: 1 } // will fail as "Type 'number' is not assignable to type 'string'.(2322)"

This also works even if the type of array results was not homogenous (i.e., if it was mixed).

type Foo = {
  id: string
  results: Array<{ bar: string } | number | string>
}

Creating Utility ElementsOf

Another approach is to create a utility type that can infer the type.

type ElementsOf<T extends unknown[]> = T extends ReadonlyArray<infer E>
  ? E
  : never

What’s actually happening here?

Alex Wayne (people are so helpful on the internet!) chimed in to help explain what was going on here:

This says that if if T is a subtype of a readonly array, infer the member value from the array and return it. If T is not a read only array, then return never, indicating that inferring the member type failed. Seems like a lot of effort though.

On the other hand, this approach suggests a new way of thinking about Type generation that’s more dynamic. It leverages a few infrequently (to me) used types:

  1. The ReadonlyArray type
  2. the infer type

I put together an interactive Typescript playground here.



Hi there and thanks for reading! My name's Stephen. I live in Chicago with my wife, Kate, and dog, Finn. Want more? See about and get in touch!