DEV Community

Cover image for Going from JS to TS
mgaroz
mgaroz

Posted on

Going from JS to TS

Moving from JavaScript to TypeScript is a transition that requires time, effort, and patience. As a developer who has made this transition, I can attest to the many benefits of TypeScript. However, there are several hurdles that I had to overcome during this journey. Let's take a closer look at each of these challenges.

Learning Curve:

One of the most significant challenges of transitioning to TypeScript was the learning curve. TypeScript introduces new concepts, such as interfaces, classes, and type annotations, that I wasn't familiar with before. I had to invest time in learning these concepts and how they fit into the development process.

Javascript:

function add(a, b) {
  return a + b;
}
Enter fullscreen mode Exit fullscreen mode

Typescript:

function add(a: number, b: number): number {
  return a + b;
}
Enter fullscreen mode Exit fullscreen mode

In TypeScript, we have to specify the types of the function parameters and the return value. This was a new requirement that required some getting used to.

Configuration:

Setting up a TypeScript compiler and configuring my build tools and IDE to work with TypeScript was an additional task that I wasn't used to with JavaScript. This required me to research and understand the configuration process, which was a new challenge.

Type Annotations:

Adding type annotations to my code was a new requirement, which helped catch errors early but took some getting used to. I had to learn how to write type annotations and add them to my code, which was a challenge at first.

Javascript:

const user = {
  name: 'John',
  age: 30,
};
Enter fullscreen mode Exit fullscreen mode

Typescript:

interface User {
  name: string;
  age: number;
}

const user: User = {
  name: 'John',
  age: 30,
};
Enter fullscreen mode Exit fullscreen mode

In TypeScript, we can define interfaces to describe the shape of our objects. This makes the code more readable and easier to maintain over time.

Third-party Libraries:

Some third-party libraries that I had previously relied on did not have TypeScript support, which required me to search for TypeScript-compatible alternatives or write my type definitions. This was a time-consuming task, but it was necessary to ensure that all code was compatible with TypeScript.

Javascript

import axios from 'axios';

axios.get('https://api.example.com/data').then(response => {
  console.log(response.data);
});
Enter fullscreen mode Exit fullscreen mode

Typescript:

import axios, { AxiosResponse } from 'axios';

axios.get('https://api.example.com/data').then((response: AxiosResponse) => {
  console.log(response.data);
});
Enter fullscreen mode Exit fullscreen mode

In TypeScript, we have to import the types for third-party libraries to ensure that our code is compatible with TypeScript. This can be time-consuming, but it's necessary to ensure that our code is type-safe.

Legacy Code:

Working on an existing JavaScript project meant converting the codebase to TypeScript, which was a time-consuming process and introduced new errors. I had to spend time converting the codebase and fixing any errors that arose during the process.

Team Collaboration:

Transitioning to TypeScript with a team was a challenge, as some members were not familiar with TypeScript. Ensuring everyone followed the same coding conventions and style was crucial for successful collaboration. I had to invest time in training team members on TypeScript and ensuring that everyone was on the same page.

Benefit: Improved Code Organization

Javascript:

function add(a, b) {
  return a + b;
}

function subtract(a, b) {
  return a - b;
}
Enter fullscreen mode Exit fullscreen mode

Typescript:

function add(a: number, b: number): number {
  return a + b;
}

function subtract(a: number, b: number): number {
  return a - b;
}
Enter fullscreen mode Exit fullscreen mode

In TypeScript, we have to specify the types of our function parameters and return values. This helps to ensure that our code is more organized and easier to understand.

Benefit: Early Error Detection

Javascript:

function add(a, b) {
  return a + b;
}

add('1', 2);
Enter fullscreen mode Exit fullscreen mode

Typescript:

function add(a: number, b: number): number {
  return a + b;
}

add('1', 2); // This will give a compile-time error
Enter fullscreen mode Exit fullscreen mode

In TypeScript, we can catch errors at compile-time, which helps to ensure that our code is more robust and easier to maintain over time.


Despite these challenges, transitioning to TypeScript was a rewarding experience. The benefits of improved code organization, readability, and scalability were evident, and I found that TypeScript made it easier to catch errors early in the development process. Additionally, the use of interfaces and type annotations helped to ensure that code was more robust and easier to maintain over time.

In conclusion, transitioning from JavaScript to TypeScript is a challenging but rewarding experience. It requires time, effort, and patience to overcome the hurdles, but the benefits of TypeScript make it all worthwhile. With proper training and collaboration, developers can make a smooth transition to TypeScript and enjoy the many benefits it offers.

Top comments (7)

Collapse
 
ant_f_dev profile image
Anthony Fung

Thanks for sharing your journey. While I find TS can be more difficult to write than JS, I find the long-term benefits usually pay off - both in terms of added Intellisense in VS Code, and having the transpiler inform me of errors upfront and on the build server if I miss the error.

Collapse
 
vallerydelexy profile image
vallerydelexy • Edited

you should mention the <T> thing and
stuff.d.ts
its hard to wrap my head around those stuff.

as a beginner, its confusing as where to use the : and <T>, i see them everywhere.

and how come the stuff.d.ts is automatically applied on some project without importing, but on other project i had to write the interface.

Collapse
 
tonitammi profile image
tonitammi • Edited

This is a simple example what you can do with generic type parameters.

Arrow function with generic type parameter:

const returnAnything = <T>(param: T): T => param;

const str: string = returnAnything<string>("Hello world");
const num: number = returnAnything<number>(1);
const bool: boolean = returnAnything<boolean>(false);
Enter fullscreen mode Exit fullscreen mode

Function with generic type parameter

function returnAnything<T>(param: T): T {
  return param;
}

const str: string = returnAnything<string>("Hello world");
const num: number = returnAnything<number>(1);
const bool: boolean = returnAnything<boolean>(false);
Enter fullscreen mode Exit fullscreen mode

So basically, a generic type just tells the function that T (or any other letter. Could be also K or R or anything else) can be any type that is defined when the function is called. In these functions we are saying that returnAnything function takes an argument witch is type of T and returns value, which is also type of T. Of course we could just say that a param is type of any, but it's much more error-prone.

Dummy example:

const returnAnything = <T>(data: T): T => data;
// gives an error
const str: string = returnAnything<string>(1);

const returnAnything = (data: any): any => data;
// Doesn't give an error
const str: string = returnAnything(1);
Enter fullscreen mode Exit fullscreen mode

Finally, a slightly more reasonable example where generic typing can be used in real life applications:

interface Product {
  id: number;
  title: string;
  description: string;
  price: number;
}

interface User {
  id: number;
  username: string;
}

const getStuffFromApi = async <T>(params: string): Promise<T> => {
  try {
    const res = await fetch(`https://someapi.com/${params}`);
    const data: T = await res.json();
    return data;
  }
  catch(err: unknown) {
    const error = err as Error;
    throw Error(error.message);
  }
}
// get one product by id 
const product: Product = await getStuffFromApi<Product>("/products/2");
// get all products
const products: Product[] = await getStuffFromApi<Product[]>("/products");
// get user by id
const user: User= await getStuffFromApi<User>("/users/2");
// get all users
const users: User[]= await getStuffFromApi<User[]>("/users");
Enter fullscreen mode Exit fullscreen mode

I hope this helped a bit to understand generic typing and where it can be used :)

Collapse
 
fleskesvor_56 profile image
Eivind

Those are big topics, and probably out of scope for this article. If you want to research them yourself, "the thing" is a generic type parameter, and is used for when eg. a function takes or returns values of a number of different types. In the examples above, it could have been used with AxiosResponse to explicitly type the return value. "The .d.ts thing" is called a TypeScript definitions file, and is used to apply types to JavaScript code for use with TypeScript. In a TypeScript project, you typically only use it to write "shims" when you have JavaScript dependencies which don't provide their own type definitions.

Collapse
 
haabe profile image
Håvard Bartnes

My journey from JS towards TS took a detour via JSDoc. Although many hardcore TS users will probably argue with me on this, I found reading JSDoc annotations were so much easier than reading types and interfaces in TS.

The cool thing, and my whole point of mentioning it, is that the TypeScript parser interprets a lot of JSDoc, making it valid TS.

Collapse
 
chuzhov profile image
Dan Chuzhov

TS is for weakings )

Collapse
 
aarone4 profile image
Aaron Reese

TS forces you to think about your data shapes and functions in advance and causes pain when you have to refactor: making it less painful to think about it properly in the first place. When you do refactor it effectively works like TDD and throws up all the places your code just broke.