Typescript patterns for third party dependencies

Time to read: 4 minutes

This month I have been creating some electron apps, using typescript and the aws-sdk v3 for JavaScript. I hope to have some exciting outcomes to share in the future.

For now I'd like to share some Typescript patterns I found useful when working with the new SDK.

Return types of functions

The first one is simple, it's the use of ReturnType in combination with the typeof annotations.

Here is an example:

// ../_snippets/typescript-patterns/return-type.ts

import React, { useState, useEffect } from 'react'

const listTables = () => ({
  data: {
    message: "I am fully typed"
  }
})

const [credentials, setCredentials] =
  useState<ReturnType<typeof listTables>>()

useEffect(() => {
  setCredentials(listTables())
}, [])

So to run this through. We can set the type of our useState hook to the return type of the imported function.

This is useful for the following reasons:

  • The type of credentials will be set correctly to the functions return type.
  • We are not required to inspect the function from the 3rd party, and we don't need to have knowledge of what it returns.
  • We have not imported any typing from the third party, which is IMO an improvement over always importing a libraries typedefs just to set them as state variables.
  • If in the future, if the return type of the function changes, Typescript will complain when we try to access attributes on credentials that have changed.

Resolved return of promises

Next up is an expansion of this pattern, but enabling the use of promises:

// ../_snippets/typescript-patterns/awaited-return-type.ts

import React, { useState, useEffect } from 'react'
type Awaited<T> = T extends PromiseLike<infer U> ? Awaited<U> : T;

const listTables = () => Promise.resolve({
  data: {
    message: "I am fully typed"
  }
})

const [tables, setTables] =
  useState<Awaited<ReturnType<typeof listTables>>>();

useEffect(() => {
  const init = async () => {
    const results = await listTables();
    setTables(results);
  };
  init();
}, []);

I have included the promise function to make life easier.

So this example can be read as. The type of tables, will be the resolved value, of the promise returned by the listTables function.

This is useful, mainly because, we can say that we have returned a data type, and not a promise type.

Soon, this type will be supported natively in typescript

Wrap Up

That's all for now, I hope you have found this useful 👍