3 Ways to Add Typescript to a React Library

Adding a type-system to JavaScript.

Project Source Code

Get the project source code below, and follow along with the lesson material.

Download Project Source Code

To set up the project on your local machine, please follow the directions provided in the README.md file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.

This lesson preview is part of the Creating React Libraries from Scratch course and can be unlocked immediately with a \newline Pro subscription or a single-time purchase. Already have access to this course? Log in here.

This video is available to students only
Unlock This Course

Get unlimited access to Creating React Libraries from Scratch, plus 70+ \newline books, guides and courses with the \newline Pro subscription.

Thumbnail for the \newline course Creating React Libraries from Scratch
  • [00:00 - 00:10] TypeScript is a programming language created by Microsoft to add static types to JavaScript. It's a superset of JavaScript, which means that all functionality in JavaScript is supported in TypeScript.

    [00:11 - 00:18] We can mix JavaScript and TypeScript to allow for an easier migration between the two languages. But what is static typing?

    [00:19 - 00:34] JavaScript is a dynamic language, which means we can assign a variable, like let, by variable, equal 5, which has the type number or int. Later in our code, it would be perfectly acceptable to assign my variable to equal an array with some string, like 25.

    [00:35 - 00:43] Being a dynamic language means that we don't need to worry about what the type of a variable is. This is in contrast to languages like C# or Go, which are static languages.

    [00:44 - 00:52] When a variable gets assigned a type in C#, it cannot be changed to another type. Dynamic languages are beneficial because they allow us to quickly write code.

    [00:53 - 00:59] We don't need to worry about the types we're writing. But our code quickly becomes harder to maintain as teams and code get larger.

    [01:00 - 01:12] Static typing lets our computer keep track of variable types, so it can reduce errors and we can continue to be productive. Start by installing TypeScript as a dev dependency by running YarnAddTypeScript -dev.

    [01:13 - 01:24] TypeScript will add its own CLI tool called TSC, which we can run using YarnTSC . To initialize TypeScript in our project, run YarnTSC-init.

    [01:25 - 01:33] This will create a TS-config.json file that contains settings for TypeScript. Open TS-config.json to find a few default settings.

    [01:34 - 01:46] We'll be adding three properties to build Scroller. First, add an outdoor property with a value of .slash-dist inside the compiler options, so that the TypeScript compiler knows where to put our compiled JavaScript.

    [01:47 - 01:56] Next, we need to tell TypeScript which files we want to compile and which ones we want to ignore. We do this by adding an include and exclude outside the compiler options property.

    [01:57 - 02:13] Both properties take an array of Glauv values to match files or directories. For Scroller, we'll include any file in the source directory that has the file extension .ts and ignore the node modules directory, storybook, and disk files.

    [02:14 - 02:26] We won't be needing TypeScript to compile our developer-only files. If we wanted Scroller to continue to be JavaScript files only, but include Type Script typing for our users, we can create .d.ts files.

    [02:27 - 02:35] D.ts files provide only the type definitions of our code, not the implementation itself. It mirrors the implementation JavaScript file.

    [02:36 - 02:46] File names are important. For any implementation code in uscroller.js, we have a separate uscroller.d.ts file to describe the types given in uscroller.js.

    [02:47 - 02:57] Create a new file in the source directory called uscroller.d.ts. Here we are exporting a function called uscroller which takes an options object .

    [02:58 - 03:14] Options contains an x number, a y number, and an optional is smooth Boolean parameter defaulting to false. The return type, notated by the colon after the uscroller function, is a function that returns Type void, which means the function doesn't return anything.

    [03:15 - 03:25] Since we have an early return if window doesn't exist, there's also the possibility that undefined is returned. So the pipe operator or union in TypeScript can be thought of as an or.

    [03:26 - 03:38] Either a function is returned or an undefined is returned. Just like our implementation code has a single point of entry given in a package.json file, types also have a single entry point defined in package.json .

    [03:39 - 03:48] To have an easy public interface, create an index.d.ts file, which will export all our types. This is similar to an index.js file, but for type definitions.

    [03:49 - 03:58] Finally, we can update our package.json file to include a path to our types. Open package.json and add a types property, pointing to disk/index.d.ts.

    [03:59 - 04:04] This will instruct TypeScript where to find the type definitions for a library. You may have noticed a problem though.

    [04:05 - 04:13] Index.d.ts only exists in our source directory and not the disk directory. We want the final build of our project to be encapsulated in a single directory .

    [04:14 - 04:33] In the package.json file, update the build script to copy over any d.ts file definitions. Maybe the most straightforward way of using TypeScript is to convert our JavaScript files into TypeScript files.

    [04:34 - 04:43] There are pros and cons to using TypeScript directly. Many of our users won't use TypeScript, so it's a good idea to provide JavaScript files and TypeScript definitions in the final package.

    [04:44 - 05:00] ESBuild knows how to read and produce JavaScript files from TypeScript files, but ESBuild also doesn't run type checking, so it won't check the validity of our code. As a result, we'll need to run the TypeScript compiler to validate our code and produce the d.ts typing files in the build.

    [05:01 - 05:12] We'll start by removing any d.ts files in the source directory and removing the copy script from the package.json's build script. Update our index.js file to be an index.ts file.

    [05:13 - 05:23] And update useroller.js to be useroller.ts. Changing the file extension from JavaScript to TypeScript will tell VS Code to start validating types for our code.

    [05:24 - 05:39] You'll notice VS Code gives an error in useroller.ts after changing the file extension. In tsconfig.json, we have a property strict that makes sure we're following good TypeScript practices, which is enabled by default after running Yarn TSC- NET.

    [05:40 - 05:49] One good practice is an enforced type definition to exist, which useroller.ts doesn't contain. If TypeScript can infer a type, it automatically is given an any type.

    [05:50 - 05:57] Any in TypeScript quite literally means the type can be anything. It's a way of bypassing the type checker, so TypeScript can't help us find errors.

    [05:58 - 06:09] Using the any type is highly discouraged, which is why a strict is on by default and expects types to be defined. Update the function definition in useroller.ts to match the types given in the d.ts section.

    [06:10 - 06:29] [silence] In esbill.js, change entry points from index.js to index.ts. In our tsconfig.json file, add the following properties in the compiler options section.

    [06:30 - 06:44] Declaration, in emit declaration only, tells the TypeScript compiler to only output declaration files, which are D.ts files, and not compile JavaScript, which esbill will give for us. Navigate to package.json and update the build script for our final step.

    [06:45 - 07:00] Add an and Yarn TSC after node esbill.js to run the TypeScript compiler after esbill runs. Run Yarn Build. In the district, we now have compiled JavaScript code for es bill and declaration D.ts files for TypeScript.