In this article, we'll discuss why developers use TypeScript and the basics of its usage. Before we get started, I recently wrote about TypeScript in a previous article. In that article, I explained what it is and how to set up your environment to code with it. If you need a refresher, you can find that article here.
Why Use TypeScript?
When JavaScript was first written, its biggest appeal was its flexibility. The coding language included type conversion for specific operations, allowing developers to create algorithms that could take different data types as inputs and return possibly different outputs. For some, this freedom sounds great, but any experienced developer will point out that this lack of type safety may be its downside. Without type safety, codebases become harder to maintain, and applications become more challenging to scale. Let's quickly discuss a few positives of TypeScript:
Catch Bugs Before They Happen
By requiring developers to use static types for variables and functions, they can ensure that the data they work with is what they expect. When expecting certain types of data, you can create a more reliable algorithm. Once a static type is set, TypeScript can warn you about possible bugs before they even happen. Even the TypeScript compiler will prevent code from compiling if there is potentially a bug. With just a little more code, the code base becomes more reliable.
Scalability & Maintainability
As a codebase grows with additional features or functions, the question of efficiency arises. Will my code be used properly in other modules? How can I be sure that it will work properly? TypeScript. The ability to create types and interfaces helps you ensure that your code is being appropriately used outside of its module. In React applications, you'll pass props from component to component, and some components will be used in different contexts throughout the application. Setting up type safety with components means you can ensure that a component will work properly because you know the data the component should receive. We'll explore these ideas later. Simply put, you can have peace of mind that you will not have to revisit your code multiple times to ensure it works in multiple contexts.
Long Live Your Code
The goal of writing code is for it to be readable by others, not just for it to work. As time passes, other developers will work with your code to scale an application further or perhaps debug an issue. These developers will be entering an unknown codebase, and TypeScript helps them understand the intention of your code and gets them working faster. They'll know the data types you were expecting to input and output. While this may sound simple, the convenience cannot understated. A developer's workflow will improve immediately.
Explicit Typing
The strength of TypeScript is the ability to type your variables explicitly. TypeScript can figure out the type for a variable implicitly, but this leaves the door open for unexpected outcomes if a variable could implicitly have two types, but you only planned for one. Let's take a look at a few examples:
let author: string = "Tyler Meyer";
author = 32; // Type 'number' is not assignable to type 'string'.
console.log(author); // Will not run with the Type Error on line 2
Line 1: We explicitly state that author has type 'string'.
Line 2: We attempt to reassign author to 32, but we are blocked by TypeScript since 32 is a 'number'.
Line 3: This will not be logged until we address the issue on Line 2.
let studentGrades: number[] = [80, 85, 93];
studentGrades.push(88);
studentGrades.push("A"); // Error
studentGrades.push("97"); // Error
Line 1: We initialize an array with some grades for a student, and we explicitly state the array should only contain numbers.
Line 2: This adheres to the type inside the array, so it gets pushed in.
Line 3: An error is thrown because the argument "A" is a string, which is not assignable to the parameter of type "number."
Line 4: *Even though "97" is a number, the data type is a string so it gets rejected.
Aliases & Interfaces
As our codebase grows and we use more complex data types, the type (alias) and interface keywords become very helpful. Aliases can be used on primitive data types as well, but for my example, I'll be using the object data type.
type Author = {
firstName: string,
lastName: string,
age: number,
lovesCoding: boolean,
};
const coolAuthor: Author = {
firstName: "Tyler",
lastName: "Meyer",
age: 32,
lovesCoding: true,
};
Instead of using a generic object
type, coolAuthor
is assigned the Author
type. An alias just needs to be defined before being used. Keeping your types in a "types" directory for your project will enable our team members to using these types in their modules and keep your team on the same page.
interface Book {
title: string,
numberOfPages: number,
}
interface Textbook extends Book {
subject: string,
}
const calculusBook: Textbook = {
title: "Calculus 4 Dummies",
numberOfPages: 58,
subject: "Calculus",
};
Interfaces can only be used on object types. This is because of their ability to extend other interfaces, much like classes can be used to extend other classes. Since Textbook
extends Book
, it inherits the typing for title
and numberOfPages
along with the typing for subject
.
React With Typescript
Assuming your project is set up to transpile .tsx files (React files using TypeScript and JSX) into readable JavaScript for the browser, let's explore how you can use TypeScript to manage the flow of data through your components.
General Functions
Before I show an example of React code, let's take a look at how TypeScript is used to help validate functions.
type Person = {
name: string,
age: number,
};
function greeting({ name, age }: Person) {
return `My name is ${name}, and I am ${age} years old.`;
}
greeting({ name: 'Tyler', age: 32 }); // Will successfully run.
greeting({ name: 'Ash', profession: 'Photographer' }); // Error
greeting({ name: 'Sadie', age: '1' }); // Error
By creating an alias beforehand, we can destructure our input object parameter for the keys we want to use in the greeting
function. The first function call follows the explicit types set by the alias and will run without any typing errors. The second function call doesn't use the age
property and will throw a typing error. The third function call using a 'string' type instead of a 'number' type for the age
property and will throw a typing error.
React Function Components
Components in React are made by declaring a function and returning JSX (HTML-like code) to render on the page. We pass props from a parent node to a child node to create dynamic content. These props from the parent component are placed into the parameters of the child component as an object with keys named after the props. Since we'll know the props, it makes sense that we'll want to destructure them in the child component. Now it's time to set up type safety with TypeScript. Make sure you use the .tsx extension on your component files.
import React from 'react'
function App() {
return (
<div>
<h1>This is my child:</h1>
<Child
person={{
name: "Tyler",
age: 32,
profession: "Software Developer",
}}
/>
</div>
);
}
type ChildProps = {
person: {
name: string,
age: number,
profession: string,
}
};
function Child({ person }: ChildProps) {
return (
<ul>
<li>{`Name: ${person.name}`}</li>
<li>{`Age: ${person.age}`}</li>
<li>{`Profession: ${person.profession}`}</li>
</ul>
);
}
Conclusion
When transitioning from JavaScript to TypeScript, you're inheriting a new coding language that puts up guardrails to help the developer write reliable code with fewer bugs as a project scales. While you may initially be writing more code, you'll save time in the future because fewer bugs will be encountered and fewer refactors to account for the type conversion from JavaScript.
Happy Coding!
Tyler Meyer
Sources:
https://medium.com/@ZaradarTR/why-i-typescript-aa891184279b
https://www.w3schools.com/typescript/typescript_simple_types.php
https://www.w3schools.com/typescript/typescript_arrays.php
https://www.w3schools.com/typescript/typescript_aliases_and_interfaces.php
https://www.w3schools.com/typescript/typescript_functions.php
Top comments (0)