How to reuse a TypeScript union type from a 3rd party @types module?

Viewed 1191

So I'm new to TypeScript and wanted to know if there's a way to reuse a union type from a 3rd party @types module.

Example, in @types/node we have the following union type for buffer encodings:

// Buffer class
type BufferEncoding = "ascii" | "utf8" | "utf-8" | "utf16le" | "ucs2" | "ucs-2" | "base64" | "latin1" | "binary" | "hex";

And if I have a utility function that passes a value through to Buffer.from() I am required to specify a union type that is compatible with the "BufferEncoding" type, I can't just use "string" like so:

export function convertToBuffer(input: string | Buffer, encoding?: string): Buffer {
    if (input instanceof Buffer) return input;
    return Buffer.from(input, encoding);
}

Obviously I could just copy and paste the BufferEncoding type from @types/node but this doesn't keep my code DRY, and I am not allowed to import from @types/* modules.

export type BufferEncoding = "ascii" | "utf8" | "utf-8" | "utf16le" | "ucs2" | "ucs-2" | "base64" | "latin1" | "binary" | "hex";

export function convertToBuffer(input: string | Buffer, encoding?: BufferEncoding): Buffer {
    if (input instanceof Buffer) return input;
    return Buffer.from(input, encoding);
}

I'm not interested in using the "any" type or other methods that loosen the strictness of the type checks. I suspect what I'm asking may not be possible and that's fine.

1 Answers

So thanks very much to Aleksey for pointing me in the right direction. It turns out I had a couple of different issues here that were compounding.

  1. Types for Node core packages - it is indeed as simple as running npm install --save @types/node and then the types such as BufferEncoding are available to use without importing anything.
export function doSomething(encoding?: BufferEncoding): void { ... }
  1. Destructuring nested objects - the TypeScript compiler isn't able to infer the types of variables if you re-assign them using destructuring or otherwise.

It's a common pattern to destructure objects to pull out the variables we need:

import errors from './errors';
const { http: { BadRequestError } } = errors;

export function doSomething(err: BadRequestError): void { ... }

However, this causes problems for the TypeScript compiler and gives errors such as:

  • 'BadRequestError' refers to a value, but is being used as a type here. ts(2749)
  • Parameter 'err' of exported function has or is using private name 'BadRequestError'. ts(4078)

The solution is to avoid reassignment and reference the variables directly:

import errors from './errors';

export function doSomething(err: errors.http.BadRequestError): void { ... }
Related