Giter Club home page Giter Club logo

hegel's Introduction

Hegel Logo


Unfortunately, the project is closed and will not be developed anymore. The reasons are described here.

Getting Started | Documentation | Gitter Chat

Hegel is a type checker for JavaScript with optional type annotations and preventing runtime type errors.

  • No Runtime Type Errors. Hegel has a strong type system and soundness checks. This means that he finds any TypeError that may be thrown in runtime.
  • Optional Type Annotation. Hegel has a high-level type inference which gives you the ability to drop a type annotation.
  • Typed Errors. Hegel has a mechanism to inference and annotates which errors should be thrown by functions.
  • Using d.ts as libraries definitions. Hegel has not a custom language for library typings description. We use a lot of existed .d.ts files as the source of typings for any libraries.
  • Only JavaScript with types. Hegel has only type syntax, without any additional hard syntax sugar.

To read more about Hegel, check out Docs.

Benefits over TypeScript

  1. No unexpected runtime errors

TypeScript never will guarantee that you will not have a Type Error at Runtime. Check TypeScript non-goals point 3. Hegel is on the opposite side. We try to implement a strong and sound type system that will guarantee that your program is valid.

As example (You can try it in our playground):

const numbers: Array<number> = [];

// HegelError: Type "Array<number>" is incompatible with type "Array<number | string>"
const numbersOrStrings: Array<string | number> = numbers;

numbersOrStrings[1] = "Hello, TypeError!";

// HegelError: Property "toFixed" does not exist in "Number | undefined"
numbers[1].toFixed(1);

The same example with TypeScript (v3.8.3) compiles without any error, but you will have 2 TypeError in runtime.

  1. Ability to skip type annotation

Hegel is targeting at really powerful type inference which gives an ability to write fewer type annotations.

As example (You can try it in our playground):

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());

The same example with TypeScript (v3.8.3) will throw 2 errors and inference upperStr as Promise<any>.

  1. Typed Errors

Hegel gives you information about errors that may be thrown by functions/methods.

Example of error type inference

// If you hover at function name you will see it type as "(unknown) => undefined throws RangeError | TypeError"
function assertPositiveNumber(value) {
  if (typeof value !== "number") {
    throw new TypeError("Given argument is not a number!");
  }
  if (value < 0) {
    throw new RangeError("Given number is not a positive number!");
  }
}

As you understand, you will have the same error type in try-catch block. Example:

try {
  assertPositiveNumber(4);
} catch (e) {
  // Hegel inference `e` type as "RangeError | TypeError | unknown"
}

The same example with TypeScript (v3.8.3) will throw one error and e type will be any.

Benefits over Flow

  1. No custom library definition language

Flow.js has custom library definition languages and doesn't support the most popular TypeScript "d.ts" format. But for Hegel TypeScript "d.ts" it the only way to create type definition for library. So, every library which has TypeScript definitions should work with Hegel.

  1. Better type inference

Hegel inferences function type by function declaration when Flow inferences function type by usage. As example (You can try it in our playground):

const id = (x) => x;
// Hegel inference type of "num" variable is "number"
let num = id(4);
// And type of "str" as "string"
let str = id("4");

The same example with Flow (v0.123.0) will inference both num and str as number | string.

  1. Typed Errors

Hegel gives you information about errors that may be thrown by functions/methods.

Example of error type inference

// If you hover at function name you will see it type as "(unknown) => undefined throws RangeError | TypeError"
function assertPositiveNumber(value) {
  if (typeof value !== "number") {
    throw new TypeError("Given argument is not a number!");
  }
  if (value < 0) {
    throw new RangeError("Given number is not a positive number!");
  }
}

As you understand, you will have the same error type in try-catch block. Example:

try {
  assertPositiveNumber(4);
} catch (e) {
  // Hegel inference `e` type as "RangeError | TypeError | unknown"
}

The same example with Flow (v0.123.0) will inference e type as empty.

Installing

Step 1: check your Node.js version:

$ node -v
v12.0.0

Hegel was developed for current LTS version of Node.js (12.16.1). So, you need to have at least 12 version.

If you have less than 12 version of Node.js you may change it to 12 or latest by nvm.

Step 2: install @hegel/cli with npm globally or locally:

# globally
$ npm install -g @hegel/cli

# locally
$ npm install -D @hegel/cli

Step 3. You already can use it into your JavaScript project:

# globally
$ hegel
No errors!

# locally
$ npx hegel
No errors!

Hegel has a zero-configuration, but if you want to change settings see Configuration Section.

Step 4. Hegel is already configured, but, you need to compile your project to plain JavaScript.

  • If you use Babel: Add into .babelrc file (or create .babelrc file at the root of your project with) next content:

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

    And install @babel/preset-flow

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

    Add script inside your package.json:

    {
      "name": "your-project",
      "scripts": {
        "build": "babel directory_with_your_project_files/ -d compilation_destination_directory/"
      }
    }
  • If you don't use Babel: The same as Flow, you can use flow-remove-types.

    Install flow-remove-types:

    $ npm i -D flow-remove-types

    And add next script inside your package.json scripts section:

    {
      "scripts": {
        "build": "flow-remove-types directory_with_your_project_files/ --out-dir compilation_destination_directory/ --all"
      }
    }

Finally. You can compile your project by:

$ npm run build

Project Overview

There are few separated packages in Hegel project:

Building Hegel from source

You will need to install Git, nodejs, npm and yarn

it is HIGHLY RECOMMENDED to install nodejs (and npm) with nvm and then yarn with npm like so npm -g i yarn

required versions of sayed software are listed below

node: ^12.16.3
npm: ^6.14.4
yarn: ^1.22.4

Open Terminal and copy paste following commands

# clone the repo
git clone [email protected]:JSMonk/hegel.git

# cd into the repo
cd hegel

# install all dependencies
yarn

# build core and cli
yarn build

Tests

Currently, all tests are written for @hegel/core, so, if you will change code inside @hegel/core package, you can run tests by:

yarn test

License

Hegel is MIT-licensed (LICENSE).

hegel's People

Contributors

0xflotus avatar albanminassian avatar artalar avatar demetri0 avatar dependabot[bot] avatar devanshj avatar digis-romanchenkopv avatar gaeulbyul avatar goodmind avatar igorsirenk98 avatar ikabirov avatar jessehattabaugh avatar jsmonk avatar julian-a-avar-c avatar kapelianovych avatar leushkin avatar mavrin avatar mendaomn avatar mkantor avatar mohsen1 avatar pavelkeyzik avatar raynos avatar rikkalo avatar sobolevn avatar srg-kostyrko avatar thecotne avatar thescottyjam avatar unrealsolver avatar xnuk avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

hegel's Issues

Suggestion: List of good first issues

Hi, Artem! I was amazed by your talk on HolyJS and I want to help :)

It would be cool to create a list of simple minor improvements that one could implement to get acquainted with the project. You could file these improvements as issues here labeled with good first issue.

This would be helpful for people like me who want to help, but don't know where to start.

Failed to execute proces hegel

➜  try-hegel which hegel
/home/ruslan/.nvm/versions/node/v10.15.3/bin/hegel
➜  try-hegel hegel
Failed to execute process '/home/ruslan/.nvm/versions/node/v10.15.3/bin/hegel'. Reason:
The file '/home/ruslan/.nvm/versions/node/v10.15.3/bin/hegel' specified the interpreter '/usr/local/bin/node', which is not an executable command.

Property refinements are unsound

function test(x: { a: string | number }): { a: string } | undefined {
    if (typeof x.a === 'string') {
        return x;
    }
}

const a:  { a: string | number } = { a: 'foo' };
const b = test(a);

a.a = 1;

if (b !== undefined) {
    b.a.toUpperCase(); // runtime error
}

hegel fails to run at any conditions (variants.flatMap is not a function)

➜  try-hegel node --version
v10.15.3
➜  try-hegel hegel
(node:8609) ExperimentalWarning: The fs.promises API is experimental
variants.flatMap is not a function

Project structure (does not seem to matter):

➜  try-hegel ls -Ral
.:
итого 20
drwxr-xr-x   3 ruslan ruslan 4096 лют 20 12:44 ./
drwxr-xr-x 108 ruslan ruslan 4096 лют 20 12:25 ../
-rw-r--r--   1 ruslan ruslan   69 лют 20 12:44 .flowconfig
-rw-r--r--   1 ruslan ruslan  129 лют 20 12:42 .hegelrc
drwxr-xr-x   2 ruslan ruslan 4096 лют 20 12:45 src/

./src:
итого 12
drwxr-xr-x 2 ruslan ruslan 4096 лют 20 12:45 ./
drwxr-xr-x 3 ruslan ruslan 4096 лют 20 12:44 ../
-rw-r--r-- 1 ruslan ruslan   82 лют 20 12:45 index.js

Super Code Optimisation

Is it possible to have code optimisations like in Prepack and Closure Compiler.

In the case of DOM manipulations and JS generated CSS without continuous animations and update, generate the final rendering.

Settings format

Which file format will be better for settings description: JSON, YAML, TOML or other.

It will be so good if to variant will be added few arguments related to choice :)

Incorrect type for always function

Seems like weak polymorphism isn't working =( I tried to fix it by myself, but it was very hard, code base is complicated enough for me. I think that something wrong at generic-type.js in changeAll method. When hegel tries to change return type () => <_a> to () => 1 sourceTypes and targetTypes become empty arrays after sourceType.reduce and then this.subordinateType.changeAll don't change anything.

It would be great if you give me a hint to fix this, and I could take a look one more time, but more closely. But if it's hard to fix it would be better if you take this issue

https://jsmonk.github.io/hegel/try#GYVwdgxgLglg9mABAQwDYHdkE8DOAKADwEpEBvAKESsQCcBTKEGpUSWBRPEi632hpkgIBuStQC+5SeQgIcUFBmw4AciFSpEAXkWZceMOtQkA9CcQxIcGvWiIoWAA51teIA

Unknown type of spread tuple

const tuple: [string, number] = ["", 0];

const another = [...tuple, true] // another is unknown

Playground

Expected

another: [string, number, boolean]
// or
another: [string, number, true]

Union key does not exist in object type

type Key = "demo" | "another" | "foo" | "bar"

const Foo = {
    another: 1,
    bar: 2,
    foo: 3,
    demo: 4,
}

function get(key: Key) {
    return Foo[key] // Error here
}
Property "  'another'
| 'bar'
| 'demo'
| 'foo'" does not exist in "{
	another: number,
	bar: number,
	demo: number,
	foo: number
}"

Playground

Getters/setters not supported correctly

https://jsmonk.github.io/hegel/try#MYGwhgzhAECC0G8BQ1XQOYFMAu0BGAFAJSIprkBOOArhQHbQBMA3GagL5vQQ74EBuYENUwAubtgoBLOuiLjqdACaYAZjMxLEnTkmAB7OhFxhoAXmh1MAdzjFWAegfRsATwAOmbgAt91EFp4XnTUALZBFPjUuFIwMqqYFFRakNDE5gB8lmEReobG0FoWYAB0eEA

  • getter property type is inferred as () => number instead of number
  • if I try to define both getter and setter - there is an error Duplicated property definition!

Ideally, it should check that input type for setter and return type of getter are the same.

Question: Possible HKT support?

Hi!

Currently I'm using TypeScript as a primary language but it lacks a predictable, complete and sound type system so this project looks very promising and I'm looking forward to the first release.

The question I'd like to ask is whether you're going to support higher-kinded types?

This is a commonly requested feature in languages like TypeScript#1213 and Flow#30 and the only possible solution is lightweight higher-kinded polymorphism which is implemented in libraries like fp-ts. But the solution is far from perfect, leads to poor DX and messy code.

However fully implementing HKT in Hegel would open doors to adopting battle tested FP practices from languages like Haskell and Scala.

How to install the vscode extension?

Steps to reproduce:

  1. git clone https://github.com/JSMonk/hegel
  2. cd hegel/packages/language-server
  3. npm run compile

Output:

npm run compile                                                                                                                                                                                                                            master [8160a4c]
npm ERR! missing script: compile

Wrong type interence with objects

good interence:
cosnt fn = (a, b) => a + b;
const res = fn(1, 2) //type is number

bad inference:
const fn = (a) => a.a + a.b;
const res = fn({a: 1, b: 2}) // type is number | string | bigint, but it can be just a number

Type inference should infer union type

The type system must infer { id: undefined | number } in that case?

const create = (model) => {}
const update = (model: { id: number }) => {}

// infer ({ id: number }) => undefined
const save = (model) => {
  if (typeof model.id === 'undefined') {
    create(model)
  } else {
    update(model)
  }
}

comment syntax

Hey, cool project. Was wondering if you're planning on supporting comment syntax. I use that w/ flow.js to avoid a build step. Would be great if hegel had something similar

Feature request: Show property type on hover

Currently, types are shown on hover only for variables/functions.
It would be great to be able to see type when you hover object property.

This is a sample hover hint in typescript - (property) A.b: string.

Fluent interfaces do not work

CLI does not analyse project

I have installed @hegel/cli globally first and then locally in project. But when I type hegel command output is like this below:

$ hegel
Path "events" cannot be resolved

What can it be?
P.S.: I install CLI with npm. Node version is 13.12.0

Using tagged templates results in no error reported

As soon as tagged template is used hegel stops returning error information.

For example

// Error: Type "'1'" is incompatible with type "number"
1 + '1';

With tagged template

// no errors at all
1 + '1';
a``;

Type inference seems to work, so the problem should be at error checking.

If I run CLI against file with such code I see only TaggedTemplateExpression in output.

Properties in function arguments should be invariant

Small example:

const a: { a: number} = { a: 1 };
const b: {a : number | string } = a; // CORRECT, not allowed


function foo(obj: { a : number | string }) {}
const f: ({ a: number}) => undefined = foo; // INCORRECT, allowed

Состояние анализатора

Всем привет, заинтересовался вашим анализатором после просмотра доклада, спасибо что решили поделиться.
Решил подождать некоторое время, но сейчас захотелось попробовать его в живую.
В каком сейчас состоянии анализатор, можно ли его использовать уже в дикой среде?
Есть краткое руководство как его установить и запустить? (для тех кто не имел дело ранее с language-server).

Static Program Verification and Proofs - Correct-by-Construction

Is it possible to take a step beyond type checking and add program verification and proofs like that is found in WhyML, Dafny and Ada SPARK 2014?

Following is a WhyML example:

module MaxAndSum

  use import int.Int
  use import ref.Ref
  use import array.Array

  let max_sum (a: array int) (n: int)
    requires { 0 <= n = length a }
    requires { forall i:int. 0 <= i < n -> a[i] >= 0 }
    returns  { sum, max -> sum <= n * max }
  = let sum = ref 0 in
    let max = ref 0 in
    for i = 0 to n - 1 do
      invariant { !sum <= i * !max }
      if !max < a[i] then max := a[i];
      sum := !sum + a[i]
    done;
    (!sum, !max)

end

The key is we can have specifications like:

requires { 0 <= n = length a }
requires { forall i:int. 0 <= i < n -> a[i] >= 0 }
returns  { sum, max -> sum <= n * max }

and

invariant { !sum <= i * !max }

Problem with union arrays

This code doesn't compile(ts example):

type UnionArray = Array<number> | Array<string>;

const mapArray = (arr: UnionArray): Array<string> => {
    return arr.map(element => {
        if (typeof element === 'string') { 
            return element + 'a';
        }

        return element.toString() + 'a';
    })
}

There is error in map method:

This expression is not callable.
  Each member of the union type '(<U>(callbackfn: (value: number, index: number, array: number[]) => U, thisArg?: any) => U[]) | (<U>(callbackfn: (value: string, index: number, array: string[]) => U, thisArg?: any) => U[])' has signatures, but none of those signatures are compatible with each other.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.