Working with Third-Party JavaScript Libraries (DefinitelyTyped, @types)

Table of Contents

  • Introduction
  • The Need for Type Definitions in TypeScript
  • Understanding DefinitelyTyped and @types
  • Installing Type Definitions from DefinitelyTyped
  • Working with Libraries Without Type Definitions
  • Creating Custom Type Definitions
  • Conclusion

Introduction

TypeScript is a statically typed superset of JavaScript that enhances the development experience with features like type checking, interfaces, and more. One of the most significant advantages of TypeScript is its ability to integrate seamlessly with JavaScript libraries. However, many third-party JavaScript libraries do not provide TypeScript definitions out of the box. To bridge this gap, TypeScript users rely on type definition files, which provide type information for those libraries.

In this article, we will explore how to work with third-party JavaScript libraries in TypeScript using DefinitelyTyped and @types packages, as well as how to handle libraries that don’t have existing type definitions.


The Need for Type Definitions in TypeScript

When working with JavaScript libraries in a TypeScript project, TypeScript needs to know the types of the objects, functions, and variables that the library exposes. This is because TypeScript performs type checking at compile time, and without proper type definitions, it won’t be able to validate types or provide autocomplete features in your IDE.

For example, if you want to use a popular JavaScript library like lodash in TypeScript, you’ll need to have type definitions for it. Without the definitions, TypeScript won’t understand the library’s API and may raise errors or fail to offer helpful type suggestions.


Understanding DefinitelyTyped and @types

What is DefinitelyTyped?

DefinitelyTyped is an open-source project that provides high-quality type definitions for thousands of JavaScript libraries. The type definitions are community-contributed, and the goal of the project is to make JavaScript libraries fully compatible with TypeScript by providing type information.

These type definitions are published as npm packages under the @types scope.

What are @types Packages?

@types packages are TypeScript type definition packages hosted on npm. These packages contain .d.ts files (TypeScript declaration files) that describe the types of various JavaScript libraries. The @types namespace is used for packages that provide type definitions for libraries that don’t include them by default.

For example:

  • @types/lodash: Type definitions for the lodash library.
  • @types/jquery: Type definitions for jQuery.

When you install a library with TypeScript support, you often need to install its @types package as well.


Installing Type Definitions from DefinitelyTyped

Installing type definitions from DefinitelyTyped is straightforward. You can use npm (or yarn) to install the necessary @types package.

Step-by-Step Process

  1. Install the JavaScript library: First, install the library you wish to use with npm or yarn. npm install lodash
  2. Install the type definitions: Next, install the corresponding type definitions using the @types package. npm install --save-dev @types/lodash TypeScript will automatically detect the type definitions when you import the library into your project.
  3. Use the library in TypeScript: import * as _ from 'lodash'; const numbers: number[] = [1, 2, 3, 4]; const reversedNumbers = _.reverse(numbers); console.log(reversedNumbers); // Output: [4, 3, 2, 1]

In this example, the type definitions for lodash are installed via the @types/lodash package, allowing TypeScript to provide type safety and autocomplete features for the lodash API.

Benefits of Using @types

  • Type Safety: You get autocompletion, type checking, and error detection based on the types defined in the @types package.
  • Improved Developer Experience: IDEs can offer better support, including hover hints, type info, and error squiggles.
  • Community Support: Many widely used JavaScript libraries have well-maintained type definitions available via DefinitelyTyped.

Working with Libraries Without Type Definitions

Not all libraries come with TypeScript definitions, and in some cases, there may not be a corresponding @types package. So, how can you work with such libraries in TypeScript? Here are a few ways to handle this situation:

1. Using any Type

If you are working with a library that doesn’t have type definitions, and you’re not sure how to proceed, you can tell TypeScript to treat the library’s exports as any. This disables type checking, but it lets you use the library without TypeScript errors.

import * as SomeLibrary from 'some-library';

const result: any = SomeLibrary.someFunction();

While this works, it’s not ideal since you lose the benefits of TypeScript’s type system.

2. Using declare Statement for Missing Definitions

You can create a declaration file to inform TypeScript about the types of the external library. This is especially useful when a third-party library doesn’t have any type definitions available. You can create a .d.ts file and declare the library’s types yourself.

For example, if you’re using a library my-lib that doesn’t have type definitions, you can create a my-lib.d.ts file:

// my-lib.d.ts
declare module 'my-lib' {
export function doSomething(arg: string): number;
}

This allows TypeScript to understand the basic types and provide type checking for this specific module.

3. Contributing Type Definitions to DefinitelyTyped

If you use a library that lacks type definitions and you have the time and knowledge, you can contribute type definitions back to the community. You can create a pull request to the DefinitelyTyped repository, which will add the type definitions for others to use.

To contribute type definitions:

  • Fork the DefinitelyTyped repository.
  • Add the type definitions for your library in the corresponding folder (e.g., types/my-lib).
  • Submit a pull request for review and inclusion.

This is an excellent way to contribute back to the TypeScript community and help others who are using the same library.


Creating Custom Type Definitions

In some cases, you may need to create your own type definitions for a JavaScript library. Let’s walk through the basic steps:

1. Creating a .d.ts File

You can create a custom declaration file for the library if you have specific type information available. For example, if you have a library my-lib:

// my-lib.d.ts
declare module 'my-lib' {
export function myFunction(a: string, b: number): boolean;
}

2. Use Custom Type Definitions in Your Code

Once you’ve created your custom type definitions, TypeScript will use them whenever you import the library:

import { myFunction } from 'my-lib';

const result: boolean = myFunction("test", 42);

3. Advanced Type Definition Techniques

If the library has a more complex API, you can dive deeper into TypeScript’s advanced types such as generics, function overloads, and type aliases to make the type definitions more comprehensive.


Conclusion

Working with third-party JavaScript libraries in TypeScript can greatly enhance your development process, provided you have the necessary type definitions. The DefinitelyTyped project and @types packages make it easy to integrate JavaScript libraries with TypeScript, offering type safety, autocompletion, and error detection.

However, for libraries without existing type definitions, you can still work with them using techniques like the any type, custom declaration files, or by contributing your own type definitions to the community.

By incorporating proper type definitions, you will significantly improve the maintainability and reliability of your TypeScript projects when working with third-party JavaScript libraries.