The following things are necessary to migrate from JavaScript to TypeScript:
Let us assume we have JavaScript files that need to be converted into TypeScript. We know that, when we compile a TypeScript file, it produces corresponding JavaScript file with the same name. Here, we need to ensure that our original JavaScript file which acts as input cannot have in the same directory so that TypeScript does not override them.
From the above point, we are going to assume that our directory is set up like the below structure. Here, we kept all the output files in an output directory called "built."
We can use the following process to migrate from JavaScript to TypeScript:
First, we need to add a tsconfig.json file in our project. TypeScript uses a tsconfig.json file for managing our project's compilation options, such as which files we want to include and exclude.
{ "compilerOptions": { "outDir": "./built", "allowJs": true, "target": "es5" }, "include": [ "./src/**/*" ] }
In the above file, we are specifying a few things to TypeScript:
We know, most JavaScript projects have an integrated build tool like gulp or webpack.
We can integrate projects with webpack in the following ways:
a) Run the following command on terminal:
$ npm install awesome-typescript-loader source-map-loader
In webpack integration, we use awesome-typescript-loader (a TypeScript loader) combined with source-map-loader for easier debugging of source code.
b) Merge the module config property in our webpack.config.js file to include the following loaders:
module.exports = { entry: "./src/index.ts", output: { filename: "./dist/bundle.js", }, // Enable sourcemaps for debugging webpack's output. devtool: "source-map", resolve: { // Add '.ts' and '.tsx' as resolvable extensions. extensions: ["", ".webpack.js", ".web.js", ".ts", ".tsx", ".js"] }, module: { loaders: [ // All files with a '.ts' or '.tsx' extension will be handled by 'awesome-typescript-loader'. { test: /\.tsx?$/, loader: "awesome-typescript-loader" } ], preLoaders: [ // All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'. { test: /\.js$/, loader: "source-map-loader" } ] }, // Other options... };
In this section, we have to rename our .js file to .ts file. Similarly, if our file uses JSX, we will need to rename it to .tsx. Now, if we open that file in an editor which support TypeScript, some of our code might start giving compilation errors. So, converting files one by one allows handling compilation errors more easily. If TypeScript finds any compilation errors during conversion, it still able to translate the code just like Word will print our documents.
After moving js file to ts file, immediately, TypeScript will start Type Checking of our code. So, we get diagnostic errors in our JavaScript code. Some of the errors we may encounter are listed below:
a) We can suppress errors with using any, e.g.:
In the below code, we can delete the error by using the type assertion.
var foo = 123; var bar = 'hey'; bar = foo; // ERROR: cannot assign a number to a string bar = foo as any //Ok
b) Function with less or more arguments:
function display(name, age, height) { let str1 = "Person named " + name + ", " + age + " years old"; let str2 = (height !== undefined) ? (" and " + height + " feet tall") : ''; console.log(str1 + str2); } display( "Rohit", 32);
In the above code, the function display() takes three arguments: name, age, and height. We can call this function with two values: "Rohit" and 23. It is perfectly valid with JavaScript because in JavaScript if an expected argument to a function is missing, it assigns the value undefined to the argument.
But, the same code in TypeScript will give the compilation error: Expected three arguments but got two. To remove this error, we can add an optional parameter sign to the argument height and annotate our code as below:
function display(name: string, age: number, height?: number) { let str1: string = "Person named " + name + ", " + age + " years old"; let str2: string = (height !== undefined) ? (" and " + height + " feet tall") : ''; console.log(str1 + str2); }
c) Sequentially Added Properties
The following code is very common in JavaScript.
var options = {}; options.color = "red"; options.volume = 11;
In TypeScript, the type of options as {} is an empty object. So, color and volume doesn't exist and are not assignable. If we instead moved the declarations into the object literal themselves, we would not get any errors:
let options = { color: "red", volume: 11 };
We can also define the type of options and add a type assertion on the object literal.
interface Options { color: string; volume: number } let options = {} as Options; options.color = "red"; options.volume = 11;
JavaScript projects use third-party libraries like jQuery or Lodash. In order to compile files, TypeScript needs to know the types of all objects in these libraries. We know, TypeScript Type definition files for JavaScript libraries are already available at DefinitelyTyped. So, we don't need to install this type externally. We need to install only those types which are used in our project.
For example
For jQuery, install the definition:
$ npm install @types/jquery
For Lodash, install the definition:
$ npm install -S @types/lodash
Once, we made the changes to our JavaScript project, run the build tool. Now, we should have our TypeScript project compiled into plain JavaScript that we can run in the browser.