TypeScript Adds Incidental Complexity to Using Libraries

Inter-operating with libraries in the JavaScript ecosystem from TypeScript introduces incidental complexity due to packaging and types. There are (at least) four different ways to import a library[0] in TypeScript, each with subtle differences. Depending on the way the library is packaged you will need to pick the correct incantation.

To get the benefit of static typing for a non-typed library, you also need to add @types/name-of-lib to your dependencies. Sometimes these are no longer needed when the library adds TypeScript support as did aws-sdk which, depending on what blog post or StackOverflow question you are looking at may or may not tell you.

Finally, types in a library that has TypeScript support can be done poorly. For example, I found a rather unfortunate issue in marked.js because the Tokens union type doesn’t have a common discriminator property. That makes it not possible, or extremely hack-y to find a specific kind of element[1].

[0]

import { Lib } from 'some-lib'
import 'some-lib';
import * as Lib from 'some-lib';
const lib = require('some-lib');

[1]

export function extractMarkdownTitle(md: string): string | null {
  const lexer_output = marked.lexer(md) as marked.TokensList;

  // Hack: This isn't typeable because Tokens is not a descriminating
  // union type (Def and Space don't have a `type` prop)
  let title: any = lexer_output.find((val: any) => {
    // Without casting to `any`, this won't compile
    return val.type === 'heading';
  });

  return title ? title.text : null;
}
  • Python Type Hinting

    Python 3+ has type annotations that can be used for static type checking using a separate program. There are several competing type checkers (mypy, pyright, pyre) that can be used that are sponsored by different companies (Facebook, Microsoft).

  • Typescript Undermines the Value of the Javascript Ecosystem and Static Typing

    The way TypeScript adds incidental complexity to using libraries undermines the two most important values of using TypeScript and JavaScript. It makes it harder to use a non-typed library which adds friction to using the wealth of libraries available in the JavaScript ecosystem. It also makes the type system less valuable when you need to hack around poorly typed libraries or incorrect type definitions by casting to the any type.

  • Fighting the Framework

    In software development, when you are spending time trying to implement something that the framework you are using either doesn’t do or makes it harder. This is a sign of incidental complexity and that the value of using the framework might be exceeded by the additional effort to be able to use it.