QueryPie Development #7: TypeScript is Everywhere

A few years ago, TypeScript was only used partially in JavaScript. It was often the subject of discussion as people wondered, ‘Why and how do I write TypeScript?’. But the development world has changed rapidly, and now the importance is so well-known that the topic of discussion has become ‘Why DON’T you use TypeScript?’

What is TypeScript and why would I use it in place of JavaScript? [closed] (source: Stackoverflow)

In this blog, I’d like to share how I’ve developed projects using TypeScript (such as QueryPie and QueryPie Protocol) by leveraging TypeScript globally to develop it as Fullstack. Before we begin, I would like to point out that this article does not explain each method in detail due to time limitations.

Please don’t read too much into my analysis. While my break-downs might not carry too much depth, my purpose is to show how TypeScript is used widely across many platforms. Thank you in advance for reading my article!

Use TypeScript in a SPA created with React

This is probably the most common TypeScript usage pattern. The SPA environment makes it very easy to use TypeScript because it contains module bundlers such as Webpack, Paracel, and other transcoders for bundling.

React is particularly useful for TypeScript. But I need some tips for Props’ type declaration, which I will discuss soon.

Working with CRA:

Create React App (https://facebook.github.io/create-react-app/)

If you are familiar with generating a React project using the Create React App (CRA) tool, you can easily attach a --typescript flag when you create it.

$ npx create-react-app my-app --typescript

This is officially supported by CRA 2.1.0 and above. For the curious, more information can be found here!

Working with NEXT.js:

Next.js (https://nextjs.org/)

When considering Server-Side Rendering (SSR), due to the need for Search Engine Optimization (SEO), NEXT.js is often used very directly. NEXT.js is a tool whose file-path-based routing is both an advantage and a disadvantage. It also enjoys a great deal of popularity with its many convenience features. NEXT.js officially supports TypeScript but requires the plug-in below:

npm install --save @zeit/next-typescript

Creating a project with NEXT.js and the following settings is somewhat complicated, so check out the broken-down steps here.

Declaring React Props Type:

In React, the type of Props are declared as Interface or Type and specified as Generic in the React.Component syntax.

interface IProps {}
class Info extends React.Component<IProps> {

You can use HOCs for status management tools such as Redux and MobX, and often inject other properties of Props. So the Props Type Declaration becomes increasingly complex and is not an element inserted into the parent process using this component, so the Props Type Declaration becomes filled with Optional.

This issue is resolved using TypeScript’s Omit and Partial to define the props exposed to the outside accurately.

type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;

interface InjectedProps {
   appStore: IAppStore;
}

interface IProps extends InjectedProps {
   object: IObjectPanel;
}

type ExposedProps = Omit<IProps, keyof InjectedProps> & Partial<InjectedProps>;
@inject('appStore')
class Info extends React.Component<IProps> { ... }
export default Info as React.ComponentType<ExposedProps>;

Finally, Info becomes a code that exposes the React component in the form of React.ComponentType<ExposedProps>. It’s a bit complicated, but we can specify exactly what Props we want to receive from the parent component. Once we understand Generic and Type combinations of these TypeScripts allows the freedom to write them the way we need them.

Use TypeScript in SPAs that deal with complex data:

Complex apps dealing with complex data reveal the true value of Typescript.

Working with strictNullChecks:

For robust TypeScript code, I recommend that you turn on the options below in tsconfig.json.

// tsconfig.json
{"compilerOptions": {
"strictNullChecks": true,
}}

When this option is turned on, the TypeScript compiler will display an error in any code that can be defined as null or undefined. This prevents TypeError, the most common error that can occur when dealing with primarily complex data in JS. It is a terrifying error comparable to Java’s NullPointerException (java.lang.NullPointerException)!

TypeError: null or undefined has no properties

TypeScript has a variety of strict compiler options. Compared to other options, I recommend that you use strictNullChecks. For more specific compiler options for TypeScript, check out the image below:

Compiler Options (https://www.typescriptlang.org/docs/handbook/compiler-options.html)

Model Driven State Management:

When you deal with complex data, status management becomes very difficult. One of the key status management tools that SPA uses is Redux. However, because of the complex and large Action code the Redux utilizes, MobX is a popular alternative.

Redux with MobX, and the MobX-state-tree

And then there’s a tool called MobX-state-tree, which enables model-based state management to handle complex data.

The MobX-state-tree is written in TypeScript to provide a complete type declaration of the model. It also provides a complete type of reasoning for the declared model to reduce the code’s flaws in handling the data dramatically.

User model defined through the MobX-state-tree
Reasoning User model type object named ‘me’ defined through MobX-state-tree

I have previously made a detailed comparison of the state of management tools used in SPA here, but for now, it’s only available in Korean. Sorry about that! If you would like to learn more, I’m sure a quick Google search will bring up some good results!

Working with TypeScript in Node.js:

Many people don’t know how to use TypeScript in Node.js because it can get a little complicated. In comparison, using TypeScript in React is easier due to its accessible and convenient tools. But surprisingly, using TypeScript in Node.js is quite simple.

Working with TSC:

Include TypeScript in the Node.js project, and ts files created with TypeScript are compiled as regular JavaScript files through the TypeScript Compiler (TSC). And then you can run through Node.js as you used it before.

$ npm install -g typescript @types/node
$ tsc app.ts    // compile
$ node app.js    // run!

If the code changes in combination with Nodemon (a widely used Node.js restart tool), then you can develop it by rerunning the app after compilation.

$ tsc --watch app.ts
$ nodemon app.js

Working with TS-Node + Nodemon:

However, we recommend using TS-Node during the development phase because compiling every time is inconvenient, and it’s chaotic to have constantly-created temporary .js files stacking up. For more information on ts-nodes, check here.

$ nodemon --exec 'node -r ts-node/register' app.ts

Operating Node.js through Nordeman's exec parameter can include various settings that apply to Node.js, and multiple commands to operate before Node.js is enabled, which is very highly utilized.

However, since TS-Node compiles TypeScript every time, we recommend compiling JavaScript files through TSC in Productions.

Typed ORM enjoyed with sequelize-typescript:

Sequelize is one of the most famous Object-relational mapping (ORM) tools used in Node.js . The most significant disadvantage when using Sequelize is that it is difficult to define a model without an auto-complete or type check.

Sequelize (http://docs.sequelizejs.com/)

Sequelize-typescripts allow you to define models with a familiar Class and make perfect autocomplete and type checks. For more information on Sequelize-typescript, check out this link.

Model Definition of Sequelize-Typscript is very intuitive. It’s very similar to Java Persistent API (JPA).

Using TypeScript in AWS Lambda:

A concept called Serverless means only an immediate execution environment in which a specific code is operated when needed and then disappears. It’s not a concept that’s separate and requires management, like a physical or logical server. The most famous of these Serverless services is AWS’s Lambda.

Lambda Introduction to AWS Lambda Site (https://aws.amazon.com/lambda/)

Versions 6.10 and 8.10 of Node.js provide Lambda. By default, you can write and run Typescript like in Node.js. Also, there are AWS Serverless Framework and Serverless Application Model (SAM) available as open sources for easy testing and Lambda deployment.

The simple use of these is SAM, which can be run using SAM CLI. Here are some instructions on how to install it.

Working with Lambda + Webpack + TS-loader:

Because Lambda has a 50MB limit on source code capacity, it is advantageous to bundle it with Webpack. I suggest using TypeScript with ts.loader in Webpack.

Using the webpack command to distribute the bundled results to the Sam CLI makes development and management much easier.

Using TypeScript in Electron:

TypeScript is also available for development with Electron. Thankfully, Electron fully supports TypeScript. Similar to Lambda, it is advantageous to use Webpack for bundling when using Electron.

The difference is that the source code region running on the Main Process (Node.js) of Electron should be created and bundled separately from the source codes running on the Browser Window (Web). I suggest using two separate webpack.config.js, each with a different entry portion in Webpack.

Electron offers a complete Type Definition, which saves a significant amount of effort to browse API documents

The browser-based source codes run by Electron’s Render Process are very effective in creating React in TypeScript.

Data communication between Main Process (Node.js) and Browser Window (Web) in Electron is recommended by default to use Inter-Process Communication (IPC). But IPC is one-way communication, and it isn't easy to configure and control because it operates in an event-driven manner. So it's much easier and more efficient to use the open-source electron-common-ipc, which is based on this IPC communication.

Using gRPC with TypeScript:

Google Remote Procedure Call (gRPC) is an open-source that Google developed for communication and control of internal services. It is suitable for communication between each entity in complex and multi-layered structures such as the Micro Service Architecture (MSA). You can find more information on gRPC here.

When using these gRPCs, TypeScript is used in Node.js environments to maximize convenience. Using an open source called rxjs-grpc, it’s pretty easy to convert the ‘proto file’ corresponding to the communication specification of the gRPC into TypeScript Interface and automatically generate the gRPC service.

interface converted from proto files
For easy data processing via RXJS, you can use Typesafe gRPC

Conclusion: Anywhere JavaScript is available, TypeScript can be used.

Because TypeScript is a superset of JavaScript, it can be written wherever JavaScript is used. The effect would be maximized, especially when developing front-end with React and back-end with Node.js. TypeScript allows front-end and back-end code to share type definitions and can be developed very robustly and efficiently.

I am now unable to code JavaScript without Typescript. I no longer want to develop primitive and inefficient JavaScript that needs each variable name, and each parameter defined precisely to avoid errors.

QueryPie, a big project I’m working on at CHEQUER, is a robust and efficient IDE we are developing with Electron, React, Node.js, and gRPC using TypeScript. If you’d like to learn more about QueryPie’s technical foundations, please refer to this development blog.

And if you know some JavaScript developers who are still struggling with their coding, please introduce them to the world of TypeScript and help them live a happier, easier life. :)