Fullstack Development with TypeScript

QueryPie Development #7: TypeScript is Everywhere

Woo Gim
QueryPie
9 min readFeb 18, 2019

--

📑한국어(Korean Version)- https://medium.com/p/501835592b1d

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 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 with you 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.

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 good 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 the project.

$ 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 simply. 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

The way to create a project with NEXT.js and the subsequent settings are 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 injected into the parent process using this component, so the Props Type Declaration becomes filled with Optional.

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

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 by doing this 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 displays an error in any code that can be characterized 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 detailed 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 dramatically reduce the code’s flaws in handling the data.

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

I have previously done 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 their popular 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 Nodeman’s exec parameter can include various parameters that apply to Node.js, and various 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 biggest disadvantage when using Sequelize is that it is difficult to define a model and there is no auto-complete or type check available.

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:

There is a concept called Serverless, which means only an instant 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. In addition, there are AWS Serverless Framework and Serverless Application Model (SAM) available as open sources for easy testing and deployment of Lambda.

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 because it operates in an event-driven manner it is difficult to configure and control. 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 use as a means of 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 specifically 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 robust and efficient.

In fact, 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 exactly 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. :)

--

--