Hegel 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. 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.
Let’s break down some of the most notable differences between Hegel and TypeScript.
Hegel has a powerful type inference system that enables you to write fewer type annotations.
// 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());
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.
// 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());
Hegel implemented inference and annotation for functions, which enables you to understand what error is being thrown by the code.
// 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" }
Unlike TypeScript, Hegel is not a superset language. That means constructors and features outside of JavaScript, such as decorators, private class fields, namespaces, enums, and other goodies from TypeScript, are not available in Hegel.
// 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);
any
typeSince Hegel is concerned with implementing a sound type system, it doesn’t have type coercion or an any
type.
// Error: There is no "any" type in Hegel. const something: any = null; // Error: Type cast does not exist in Hegel (null: any).call();
Hegel shares many similarities with Flow since they are both static type checker libraries. Below are some notable differences between Hegel and Flow.
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.
// 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);
Just like with TypeScript, Flow has no useful type inference for errors and will return an empty
type.
// 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" }
Instead of creating its own custom library definition like Flow, Hegel implemented the same d.ts definition as in TypeScript. Every library that has TypeScript definitions should work with Hegel.
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.
any
typeFlow has both type coercion and any
type, just like TypeScript.
// Error: There is no "any" type in Hegel. const something: any = null; // Error: Type cast does not exist in Hegel (null: any).call();
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.
# 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.
let price :number = "7"
Run the hegel
command from your project’s root directory. It will scan all .js
files for typing errors.
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.
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 or flow-remove-types.
Install the required Babel packages.
$ 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.
{ "presets": [["@babel/preset-flow", { "all": true }]] }
Now you can run it from the terminal.
npx babel index.js -d build/
You can also add it as a script inside your package.json
.
{ "scripts": { "build": "babel index.js -d build/", } }
Then, run the script.
npm run build
flow-remove-types
Install the package.
npm i -D flow-remove-types
Add the build script inside your package.json
, just like with Babel.
{ "scripts": { "build": "flow-remove-types index.js --out-dir build/", } }
Finally, run the script.
npm run build
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 where you can test its limits. Don’t forget to check out the official Hegel documentation to learn about all its features.
LogRocket is a frontend application monitoring solution that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.
In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page and mobile apps.
Debugging code is always a tedious task. But the more you understand your errors, the easier it is to fix them.
LogRocket 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 see exactly what the user did that led to an error.
LogRocket records console logs, page load times, stack traces, slow network requests/responses with headers + bodies, browser metadata, and custom logs. Understanding the impact of your JavaScript code will never be easier!
Hey there, want to help make our blog better?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowLearn how to manage memory leaks in Rust, avoid unsafe behavior, and use tools like weak references to ensure efficient programs.
Bypass anti-bot measures in Node.js with curl-impersonate. Learn how it mimics browsers to overcome bot detection for web scraping.
Handle frontend data discrepancies with eventual consistency using WebSockets, Docker Compose, and practical code examples.
Efficient initializing is crucial to smooth-running websites. One way to optimize that process is through lazy initialization in Rust 1.80.
One Reply to "Introduction to Hegel"
Dang I thought I was actually gonna learn Hegel, guess I have to read the phenomenology of spirit after all huh.