Introduction to Hegel
Tags: typescript, javascript, webdev
Published: 2020-07-16 14:05:45

---
title: Introduction to Hegel
published: true
date: 2020-07-07 16:00:39 UTC
tags: typescript,javascript,webdev
canonical_url: https://blog.logrocket.com/introduction-to-hegel/
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/0ml2v4cqqri2n5gh4eap.png
---
**Written by [Nathan Sebhastian](https://blog.logrocket.com/author/nathansebhastian/)**✏️

[Hegel](https://hegel.js.org/) is a static type checker library that helps you identify typing errors as early as possible without actually running your code. Just like TypeScript and Flow, Hegel detects any information about type errors that exist in your code while you’re writing.

Hegel incorporates many of TypeScript and Flow’s design principles, such as having type annotations and type inferences, without introducing a new language feature like [TypeScript’s enums](https://dev.to/bnevilleoneill/why-typescript-enums-suck-54kn). When using Hegel, you’re writing pure JavaScript without even needing to add a comment, as is the case with Flow.

In this guide, we’ll show how Hegel is different from both TypeScript and Flow and walk you through how to get started with Hegel in your next project.

[![LogRocket Free Trial Banner](https://i0.wp.com/blog.logrocket.com/wp-content/uploads/2017/03/f760c-1gpjapknnuyhu8esa3z0jga.png?resize=1200%2C280&ssl=1)](https://logrocket.com/signup/)

## Hegel versus TypeScript

Let’s break down some of the most notable differences between Hegel and TypeScript.

### Skip type annotation

Hegel has a powerful type inference system that enables you to write fewer type annotations.

```jsx
// Hegel
const promisify = fn => arg => Promise.resolve(fn(arg));
const id = promisify(x => x);
// And "upperStr" will be inferred as "Promise<string>"
const upperStr = id("It will be inferred").then(str => str.toUpperCase());

// TypeScript
const promisify = fn => arg => Promise.resolve(fn(arg));
const id = promisify(x => x);
// And "upperStr" will be inferred as "Promise<any>"
const upperStr = id("It will be inferred").then(str => str.toUpperCase());
```

### No unexpected runtime errors

TypeScript doesn’t aim to apply a sound or provably correct type system, meaning it doesn’t guarantee that you won’t have any type errors at runtime. Hegel does the opposite, implementing a strong type system to guarantee that your code is valid.

```jsx
// Hegel
const doubles: Array<number> = [Math.PI, Math.E];
// Error: Type "Array<number>" is incompatible with type "Array<number | string>"
const numbersToShow: Array<number | string> = doubles;
numbersToShow.push(42..toString(2));
const rounded = doubles.map(double => double.toFixed());

// TypeScript
const doubles: Array<number> = [Math.PI, Math.E];
const numbersToShow: Array<number | string> = doubles;
numbersToShow.push(42..toString(2));
// Uncaught TypeError: double.toFixed is not a function
doubles.map(double => double.toFixed());
```

### Typed errors

Hegel implemented inference and annotation for functions, which enables you to understand what error is being thrown by the code.

```jsx
// Type of "assertIsTrue" function is "(boolean) => undefined throws TypeError"
function assertIsTrue(arg) {
    if (!arg) {
        throw new TypeError("arg is invalid")
    }
}
try {
    assertIsTrue(false);
} catch (e) {
    // Type of "e" variable is "TypeError | unknown"
}

// TypeScript
function assertIsTrue(arg) {
    if (!arg) {
        throw new TypeError("arg is invalid")
    }
}
try {
    assertIsTrue(false);
} catch (e) {
    // Type of "e" variable is "any"
}
```

### No new constructors

Unlike TypeScript, Hegel is not a superset language. That means constructors and features outside of JavaScript, such as decorators, [private class fields](https://www.typescriptlang.org/docs/handbook/classes.html#ecmascript-private-fields), namespaces, enums, and other goodies from TypeScript, are not available in Hegel.

```jsx
// TypeScript
enum UserStatus {
  Active,
  Muted,
  Banned
}
class User {
  constructor(
    public name: string,
    public status: UserStatus
  ) {}
}
const Anatoly = new User("Anatoly", UserStatus.Active);

// Hegel
const UserStatus = Object.freeze({
  Active: "Active",
  Muted: "Muted",
  Banned: "Banned"
});
class User {
    name: string;
    status: $Values<$TypeOf<UserStatus>>
    constructor(name, status) {
        this.name = name;
        this.status = status;
    }
}
const Anatoly = new User("Anatoly", UserStatus.Active);
```

### No type coercion and `any` type

Since Hegel is concerned with implementing a sound type system, it doesn’t have type coercion or an `any` type.

```jsx
// Error: There is no "any" type in Hegel.
const something: any = null;

// Error: Type cast does not exist in Hegel
(null: any).call();
```

## Hegel and Flow

Hegel shares many similarities with Flow since they are both static type checker libraries. Below are some notable differences between Hegel and Flow.

### Better type inference

Flow has a hard time inferring generic types, so if you want to have the right type, annotate it. This is because Flow.js infers function type by function usage.

Hegel infers function type by function declaration. As a result, Hegel inferences polymorphic type.

```jsx
// Hegel
// Type of "id" function is "<_a>(_a) => _a"
const id = x => x;
// Type of "num" variable is "number"
let num = id(4);
// Type of "str" variable is "string"
let str = id("4");
// Type of "anotherId" variable is "<_a>(_a) => _a"
let anotherId = id(id);

// Flow
// Type of "id" function is "(number | string | ((x: V$1) => V$2)) => (number | string | ((x: V$1) => V$2)"
const id = x => x;
// Type of "num" variable is "number | string | ((x: V$1) => V$2)"
let num = id(4);
// Type of "str" variable is "number | string | ((x: V$1) => V$2)"
let str = id("4");
// Type of "anotherId" variable is "number | string | ((x: V$1) => V$2)"
let anotherId = id(id);
```

### Typed errors

Just like with TypeScript, Flow has no useful type inference for errors and will return an `empty` type.

```jsx
// Type of "assertIsTrue" function is "(boolean) => undefined throws TypeError"
function assertIsTrue(arg) {
    if (!arg) {
        throw new TypeError("arg is invalid")
    }
}
try {
    assertIsTrue(false);
} catch (e) {
    // Type of "e" variable is "TypeError | unknown"
}

/* @flow */
function assertIsTrue(arg) {
    if (!arg) {
        throw new TypeError("arg is invalid")
    }
}
try {
    assertIsTrue(false);
} catch (e) {
    // Type of "e" variable is "empty"
}
```

### No custom library definition language

Instead of creating its own [custom library definition](https://flow.org/en/docs/libdefs/) like Flow, Hegel implemented the same [d.ts definition](https://www.typescriptlang.org/docs/handbook/declaration-files/introduction.html) as in TypeScript. Every library that has TypeScript definitions should work with Hegel.

### Hegel is implemented in JavaScript

Flow is implemented mainly in OCaml, which makes it hard for JavaScript developers to contribute to the project.

Hegel is implemented in JavaScript so that developers who use it can help resolve any PRs or issues that arise in the future.

### No type coercion and `any` type

Flow has both type coercion and `any` type, just like TypeScript.

```jsx
// Error: There is no "any" type in Hegel.
const something: any = null;

// Error: Type cast does not exist in Hegel
(null: any).call();
```

## Getting started with Hegel

To start using Hegel in your project, install its CLI package from the terminal. Please note that you need to have Node.js version 12 or higher.

```jsx
# globally
$ npm install -g @hegel/cli

# locally
$ npm install -D @hegel/cli
```

Once installed, create a new `index.js` file and write a variable with type annotation.

```jsx
let price :number = "7"
```

Run the `hegel` command from your project’s root directory. It will scan all `.js` files for typing errors.

```jsx
hegel
./index.js:1
> 1 | let price :number = "7"
    |    ^^^^^^^^^^^^^^^^^^^ Type "'7'" is incompatible with type "number"
```

And just like that, you’re all set up! You don’t need to create a `.tsx` file or write `@flow` comment on your file.

## Setting up for production

Just like Flow, a JavaScript runtime engine such as Node will throw an error when you run the file because it doesn’t recognize the annotation syntax.

To make it run properly, you have to strip away Hegel typing syntax with either [Babel](https://babeljs.io/) or [flow-remove-types](https://www.npmjs.com/package/flow-remove-types).

### Using Babel

Install the required Babel packages.

```jsx
$ npm i -D @babel/core @babel/cli @babel/preset-flow
```

Write a `.babelrc` file at the root of your project and use the following preset.

```jsx
{
  "presets": [["@babel/preset-flow", { "all": true }]]
}
```

Now you can run it from the terminal.

```jsx
npx babel index.js -d build/
```

You can also add it as a script inside your `package.json`.

```jsx
{
  "scripts": {
    "build": "babel index.js -d build/",
  }
}
```

Then, run the script.

```jsx
npm run build
```

## Using `flow-remove-types`

Install the package.

```jsx
npm i -D flow-remove-types
```

Add the build script inside your `package.json`, just like with Babel.

```jsx
{
  "scripts": {
    "build": "flow-remove-types index.js --out-dir build/",
  }
}
```

Finally, run the script.

```jsx
npm run build
```

## Conclusion

Hegel is a new static type checker library that seeks to bring together all the best parts of TypeScript by combining a static, strong type system with great type inference. It attempts to implement a minimalist but completely static type checker using pure JavaScript so you don’t need to use specific file extensions or comments to work with it.

Hegel also comes with an [interactive online editor](https://hegel.js.org/try#DYUwLgBADgTglgYxALggOwK4FsBGIYQC8EARAOwlA) where you can test its limits. Don’t forget to check out the official [Hegel documentation](https://hegel.js.org/docs) to learn about all its features.

* * *
## [LogRocket](https://logrocket.com/devto): Debug JavaScript errors easier by understanding the context 

Debugging code is always a tedious task. But the more you understand your errors the easier it is to fix them. 

[LogRocket](https://logrocket.com/devto) allows you to understand these errors in new and unique ways. Our frontend monitoring solution tracks user engagement with your JavaScript frontends to give you the ability to find out exavtly what the user did that led to an error. 

![](https://i1.wp.com/blog.logrocket.com/wp-content/uploads/2020/06/reproduce-javascript-errors.gif?ssl=1)

LogRocket records console logs, page load times, stacktraces, slow network requests/responses with headers + bodies, browser metadata, and custom logs. Understanding the impact of your JavaScript code will never be easier. 

[Try it for free.](https://logrocket.com/signup/) 
* * *

The post [Introduction to Hegel](https://blog.logrocket.com/introduction-to-hegel/) appeared first on [LogRocket Blog](https://blog.logrocket.com).