The Type Linter for JS

Overview

TypL

The Type Linter for JS.

Overview

TypL provides optional type annotations for JS programs, so you can verify that you haven't mixed incompatible value-types in any operations (which can cause bugs!). However, TypL takes a different approach from the more well-known TypeScript and Flow tools.

As a quick glance at the differences:

  • not a typed-language variant of JS, but rather a (type) linter in the truest sense: TypL checks code against a set of opinions (that you control!) about how types should be treated in your program; with a heavy emphasis on type inferencing, you can run type linting on existing JS programs without any code changes

  • for type annotations, uses only standard valid JS syntax (ES6 template tags), so type-annotated code can be executed without any compilation step if desired (as long as the runtime library is present)

  • shifts focus from "typing your variables" to "typing your values and expressions"; variables optionally get assigned "implied types" from the annotated value-types

  • provides compile-time static type checks as well as runtime dynamic type checks (assertions), both of which are optional

  • completely configurable (like ESLint), so you're always in control of what is reported as a type error or not -- for example, you decide if some specific type conversion/coercion is allowed, etc

TypL is still in early development. For more information, please see: TypL.dev.

Run

bin/typl --file=./some-code.js

or:

node ./lib/cli.js --file=./some-code.js

Test

npm test

Project Champions

I would like to thank the following people for their generous sponsorship as a project champion. You are awesome!

License

All code and documentation are (c) 2019 Kyle Simpson and released under the MIT License. A copy of the MIT License is also included.

Comments
  • Always allow assignment to tagged:

    Always allow assignment to tagged:"any"

    • [x] Always allow assignment to tagged:"any" but don't overwrite the type
    • [x] allow call-expression arguments if the corresponding parameter type is any
    • [x] if a function signature's return is set to any, return statements need to allow any return values
    • [x] apply isAssignemntAllowedin other relevant places: https://github.com/getify/Typl/pull/28#pullrequestreview-207108731
    opened by mraak 18
  • Help in Typl ESLint Plugin

    Help in Typl ESLint Plugin

    Hi @getify I'm working on eslint plugin for your nice type checker 🌟 .

    I'm confused how can I push the errors into the eslint API 😕.

    I think that doing it as so in ESLint will give the Developer good experience to integrate with Editors and CI tasks. So I went with 0 rules and I'm trying to use a processor to type check the files and I get interesting data from you checker!

    I hope you can guide me a little bit on how I can continue with this approach. Thanks in advance.

    opened by Attrash-Islam 9
  • Enforce bool type check

    Enforce bool type check

    Enforce bool type check on if, test condition of for, while, and do..while loops (like in ternary ? : operator).

    var i = 3; if(i){ // should report an error }

    opened by mraak 9
  • #39 tests for array checking

    #39 tests for array checking

    I made the tests for Array stuff. You will see there are errors happening from tuple onwards.

    Basically in a case like this, it finds errors in both assignments, instead of just the bottom one.

    var x = array`(int | string)[]`;
    x = [ 1, 2, "hello", 4 ];		// OK!
    x = [ 1, 2, true, 4 ];			// error
    

    This is because it recognizes the array as type any instead of type of ints and/or strings.

    opened by mraak 3
  • Some words on performance?

    Some words on performance?

    I saw you request code on Twitter for something called "TypL" so, I googled. Interesting use of tagging! I like the idea of this library a lot. But I wouldn't be me if I didn't get curious. 😄

    Taking a quick look at TypL makes me wonder if performance won't be an issue. Since it's active at runtime as well, doesn't it call a function for every type (because that's what tags are)? If you have a lot of inline typing (loops with large datasets and such) I can imagine this adding some overhead, especially if you're already working with other libraries that have type validation (like MST).

    In the same breathe I'd like to mention file size. Can't that be a bit much, too?

    Both of these are of course minor concerns, but I couldn't find much about them yet so I figured... Might as well ask.

    opened by RWOverdijk 2
  • Support array-of-type annotation syntax

    Support array-of-type annotation syntax

    Need to support this syntax for annotating an array of values of a certain type:

    var x = array`int[]`;
    var y = array`int[]``[1,2,3]`;
    var z = array`int[]``${y}`;
    
    x = [1,2,3];   // OK!
    y = [4,5,6];   // OK!
    z = x;   // OK!
    

    Non-empty arrays (by default they're allowed to be empty):

    var x = array`int[]``${ [] }`;  // OK, allowed to be empty
    var y = array`int[+]``${ [] }`;   // error, not allowed to be empty
    

    Array of various types (union types):

    var x = array`(int | string)[]`;
    
    x = [ 1, 2, "hello", 4 ];   // OK!
    

    Multidimensional arrays:

    var x = array`int[][]`;
    var y = array`int[][][]`;
    var z = array`(int | string)[][]`;
    
    x = [
      [1,2,3],
      [4],
      [5,6],
      [7,8,9,10]
    ];   // OK!
    
    y = [
      [
        [1,2,3],
        [4,5,6],
        [7,8,9]
      ],
      [
        [1,0,0],
        [0,1,0],
        [0,0,1]
      ]
    ];   // OK!
    
    z = [
      [1,"hello"],
      [2,3,"world"],
      ["ok"],
      [42]
    ];   // OK!
    

    Tuple, Nested Tuple:

    var x = array`<int,string>`;
    var y = array`<<int,string>,bool>`;
    
    x = [ 42, "hello world" ];   // OK!
    y = [ x, true ];   // OK!
    

    Array of tuples:

    var x = array`<int,string>[]`;
    
    x = [
      [42,"hello"],
      [10,"world"]
    ];   // OK!
    

    Tuple of arrays:

    var x = array`<int[],string[]>`;
    
    x = [
      [1,2,3,4],
      ["hello","world"]
    ];   // OK!
    

    Array of tuples of arrays:

    var x = array`<int[],string[]>[]`;
    
    x = [
      [
        [1,2,3,4],
        ["hello","world"]
      ],
      [
        [5,6],
        []
      ],
      [
        [7],
        ["very","cool","stuff"]
      ]
    ];   // OK!
    
    opened by getify 2
  • Bloating output code?

    Bloating output code?

    Very interesting approach! I am wondering wether it is worth adding to the output JS all those extra functions necessary to validate on runtime? What's the mindset on that?

    opened by afuggini 1
  • Treat IIFE as a validated call-expression

    Treat IIFE as a validated call-expression

    var y = (function foo(x = number){
       return String(x);
    })(true);
    

    Here, error should be reported about true not matching x = number, and also y should be implied as string type.

    opened by getify 1
  • use `isAssignmentAllowed(..)` for arguments and return values

    use `isAssignmentAllowed(..)` for arguments and return values

    This example currently shows errors for both the argument type mismatch and the return type mismatch. Should use the same check/rules (number subtypes, etc) as normal assignment, and show no errors.

    function foo(x = number) {
    	if (x > 4) {
    		return x;
    	}
    	return int`0`;
    }
    
    var y = foo(int`3`);
    
    opened by getify 1
  • Narrower number type inference

    Narrower number type inference

    Infer narrowest possible numeric types from number literals:

    var x = 3;   // infer 'int'
    var y = 3.14;   // infer 'finite'
    var z = NaN;  // infer 'number'
    

    This will be particularly effective once #6 is done.

    opened by getify 1
  • Multi-pass handling bugs

    Multi-pass handling bugs

    In this snippet, during the first pass, x is a 'string', but during the second pass, it should be re-typed as an 'int' (via the foo(2) call and its return value), and thus the x = "hello" assignment should report an error. However, x is still assumed a 'string' on the second pass, and thus the x = foo(2) is the statement that reports the error.

    function foo(v) {
        return v;
    }
    var x = foo(2);
    x = "hello";
    

    In this snippet, during the first pass, the foo(..) function assumes a return type of 'int', then on the second pass (because of "hello" being assigned to v parameter), the return type should be changed to 'string', and then return 42 should report an error. However, the function return type is still assumed as 'int', and thus return v reports the error.

    function foo(v) {
        if (true) {
            return v;
        }
        return 42;
    }
    var x = foo("hello");
    
    opened by getify 0
  • Documentation functionality

    Documentation functionality

    I believe TypL could benefit from implementing documentation functionality.

    Types are useful for documentation but they're only a partial strategy. If a developer were to use TypL for a project and also wanted documentation they'd likely reach for JSDoc and omit type information. JSDoc is widespread but it's an old, inactive project with clunky, generally disliked syntax (I only have anecdotal evidence for this claim).

    I propose TypL could enter this field to 1) give developers a modern documentation system and 2) enhance TypL itself with more detailed runtime error descriptions. This would both bring more attention to TypL itself and increase the value of and use cases for TypL.

    Nice IDE integration for JSDoc-like tooltips would be a big bonus too.

    Usage example with rough API:

    function getCommaSeparatedNumberStringPair (aBool = bool, aNumber = number, aString = string) {
      return aBool ? string`${aNumber}, ${aString}` : string`No bueno.` 
    }
    documentation (getCommaSeparatedNumberStringPair, {
      description: 'This function joins a number and string together to create a new string.',
      parameters: {
        aBool: 'some description of aBool',
        aNumber: 'some description of aNumber',
        aString: 'some description of aString',
      },
      returns: 'aNumber comma separated from aString if aBool is true, otherwise a default message.',
    })
    
    getCommaSeparatedNumberStringPair(anArbitraryBool, anArbitraryString)
    

    Resulting runtime error:

    TypL Error: 
      Invalid types for getCommaSeparatedNumberStringPair.
      Received Arguments:
         1. VALID: a boolean value
         4. INVALID: a string value
         5. INVALID: no value given
      Function Parameters:
         1. aBool: boolean - some description of aBool
         2. aNumber: number - some description of aNumber
         3. aString: string - some description of aString
      Suggestion:
        Fix Received Argument types for #2 and #3 to match Function Parameters.
    

    "Function Parameters" above is where we see the mixture of TypL's type information and the user-generated documentation. I'm sure we could come up with other benefits of mixing type information and documentation as well.

    documentation could be configurable to spit out more or less information. For example: a developer could configure the output to include description and returns, unlike what you see above.

    Benefits of a function-based API (as opposed to JSDoc style comments):

    1. Modularity
    2. Composability
    3. Flexibility
    4. Ergonomic
    5. Smaller learning curve, no special syntax
    6. Automatic IDE support for syntax

    Basically, it's JS, do what you want to.

    Simple example showing how an application could have a common dictionary of terms to be used around the codebase

    // commonDictionary.docs.js
    export const organizationId = string`the id for an organization`
    export const organizations = string`a list of organizations`
    
    
    // myModule.js
    import { organizationId, organizations } from './commonDictionary.docs.js'
    
    const deleteOrganization = (organizationId = string, organizations = array) => {
      return organizations.filter (organization => organization.id !== organizationId)
    }
    documentation (deleteOrganization, {
      description: 'This function removes an organization',
      parameters: {
        organizationId,
        organizations,
      },
      returns: 'the updated organizations',
    })
    
    const updateOrganization = (organizationId = string, organizations = array, updateProperties = object) => {
      return organizations.map (organization => {
        return organization.id === organizationId
          ? { organization, ...updateProperties }
          : organization
      })
    }
    documentation (updateOrganization, {
      description: 'This function updates an organization',
      parameters: {
        organizationId,
        organizations,
        updateProperties: 'the properties to update an organization with',
      },
      returns: 'the updated organizations',
    })
    
    opened by kee-oth 6
  • Will TypL cover 100% of JS semantics?

    Will TypL cover 100% of JS semantics?

    Other projects like TypeScript struggle with providing ergonomic ways of typing code written in a functional style. And at least at some point, TypeScript wasn't expressive enough to type certain functional programming techniques at all. I'm not sure if this is still true but I suspect it is. TypL works a bit different though because it works on value-types instead of variables so I imagine it's more flexible.

    1. Are there things in JS that you can do but are not possible for TypL to type?
    2. How does TypL fair with regards to typing functional programming techniques?
    3. Does TypL make tradeoffs that favor a particular style of coding?

    I know TypL isn't done yet so I'm fine with the answers to refer to assumptions and goals for TypL.

    Thanks!

    opened by kee-oth 11
  • Why were tag functions chosen for the API?

    Why were tag functions chosen for the API?

    TypL looks extremely interesting! Thank you for putting so much work into it already!

    I have kind of a surface level question: why were tag functions chosen for the API? I'm sure there are good reasons but from the outside-in perspective, it seems that normal function calls would be a little more ergonomic since there's a good bit less syntax:

    Using tag functions:

    function isEven(v = number) {
       return bool`${ v % 2 == 0 }`;
    }
    
    var x = number`42`;
    var kind = bool`${ isEven(x) }`;
    

    vs

    Using "regular" functions:

    function isEven(v = number) {
       return bool( v % 2 == 0);
    }
    
    var x = number(42);
    var kind = bool( isEven(x) );
    

    Thanks!

    question 
    opened by kee-oth 5
  • Checker tests keep failing

    Checker tests keep failing

    Bug report

    Checker tests keep failing on my end:

    > [email protected] test /home/mohamededrah/Projects/Oss/TypL
    > node scripts/node-tests.js
    
    
    **********************************
    ********** TESTING SRC ***********
    **********************************
    
    TypL Test Suite (36)
    
    Passed: 'Runtime: API' (14/14)
    Passed: 'Runtime: any(..)' (4/4)
    Passed: 'Runtime: undef(..)' (10/10)
    Passed: 'Runtime: nul(..)' (11/11)
    Passed: 'Runtime: string(..)' (8/8)
    Passed: 'Runtime: bool(..)' (10/10)
    Passed: 'Runtime: number(..)' (10/10)
    Passed: 'Runtime: finite(..)' (11/11)
    Passed: 'Runtime: int(..)' (13/13)
    Passed: 'Runtime: bint(..)' (13/13)
    Passed: 'Runtime: symb(..)' (10/10)
    Passed: 'Runtime: array(..)' (11/11)
    Passed: 'Runtime: array(..), parse shapes only' (8/8)
    Passed: 'Runtime: array(..), shape parse failure' (10/10)
    Passed: 'Runtime: array(..), shape: int[]' (8/8)
    Passed: 'Runtime: array(..), shape: <int[][],string>[]' (10/10)
    Passed: 'Runtime: object(..)' (10/10)
    Passed: 'Runtime: func(..)' (10/10)
    Passed: 'Runtime: regex(..)' (9/9)
    Passed: 'Checker: API' (1/1)
    Passed: 'Checker: #6 number sub-types' (2/2)
    Passed: 'Checker: #7 enforce bool type check in conditionals' (2/2)
    Passed: 'Checker: #8 any' (2/2)
    Passed: 'Checker: #9 undef' (2/2)
    Passed: 'Checker: #17 Narrower number type inference' (2/2)
    Passed: 'Checker: #33 Treat IIFE as a validated call-expression' (2/2)
    Passed: 'Checker: #34 check tagged-type simple literals' (2/2)
    Passed: 'Checker: #39 array-of-type annotation' (1/1)
    Passed: 'Checker: #39 Non-empty arrays ' (1/1)
    Passed: 'Checker: #39 Non-empty arrays' (1/1)
    Failed: 'Checker: #39 Array of various types (union types)' (1/1)
      num errors
        expected: 1
        actual: 2
    Failed: 'Checker: #39 multidimensional arrays' (1/1)
      num errors
        expected: 0
        actual: 1
    Failed: 'Checker: #39 Tuple, Nested Tuple' (1/1)
      num errors
        expected: 1
        actual: 2
    Failed: 'Checker: #39 Array of tuples' (1/1)
      num errors
        expected: 0
        actual: 1
    Failed: 'Checker: #39 Tuple of arrays' (1/1)
      num errors
        expected: 0
        actual: 1
    Failed: 'Checker: #39 Array of tuples of arrays' (1/1)
      num errors
        expected: 0
        actual: 1
    
    Failed (6/214)
    
    **********************************
    ********** TESTING SRC ***********
    **********************************
    
    npm ERR! Test failed.  See above for more details.
    

    this happens after i run npm install

    I did some exploring it seems that the tests (at least for me) start failing at commit 8286faf664bafa36c16d17964142e4fee61fd581
    is this a problem on my end or are the test broken ?, i really like this project and would like to contribute if possible, thanks.

    How to reproduce

    Clone this repo: https://github.com/MSE99/TypL and run npm install

    Additional information

    os: Pop!_OS 20.04 (An ubuntu based linux distro) node version: 14.16.1 npm version: 6.14.1 typL version: I'm running the tests on the master branch on the latest commit.

    opened by MSE99 2
  • another good example/test

    another good example/test

    const add = x => y => x + y;
    
    const a = add(1)(2);
    const b = add('a')('b');
    const c = add(1)('b');
    
    a - 1;
    

    Expected results:

    1. Trigger an error on the add('a') call since that string value doesn't match the number type that was implied by the previous add(1) call. Ditto for the ('b') call. These errors could be configured off if you didn't want them.
    2. Expand the implied type for the x function parameter to be a union type (number | string), as well as y, so future calls can send either type for either parameter.
    3. Trigger an error on the + operation when the 1 and 'b' are added. Again, this error could be configured off.
    4. a - 1 would definitely be allowed, since a was implied as a number.

    Other results:

    cool-example 
    opened by getify 0
  • Feature for preserving run-time gathered typing info (such as from tests)

    Feature for preserving run-time gathered typing info (such as from tests)

    This is an interesting idea that fits well with TypL's vision, should explore having it incorporated.

    https://twitter.com/mpjme/status/1127113416307630080

    opened by getify 1
Owner
Kyle Simpson
I like to explore JS and FP techniques. Helping build a culture of engineering excellence for my employer.
Kyle Simpson
The Type Linter for JS

TypL The Type Linter for JS. Overview TypL provides optional type annotations for JS programs, so you can verify that you haven't mixed incompatible v

Kyle Simpson 352 Nov 24, 2022
Grupprojekt för kurserna 'Javascript med Ramverk' och 'Agil Utveckling'

JavaScript-med-Ramverk-Laboration-3 Grupprojektet för kurserna Javascript med Ramverk och Agil Utveckling. Utvecklingsguide För information om hur utv

Svante Jonsson IT-Högskolan 3 May 18, 2022
Hemsida för personer i Sverige som kan och vill erbjuda boende till människor på flykt

Getting Started with Create React App This project was bootstrapped with Create React App. Available Scripts In the project directory, you can run: np

null 4 May 3, 2022
Kurs-repo för kursen Webbserver och Databaser

Webbserver och databaser This repository is meant for CME students to access exercises and codealongs that happen throughout the course. I hope you wi

null 14 Jan 3, 2023
🌟 JavaScript Style Guide, with linter & automatic code fixer

JavaScript Standard Style Sponsored by English • Español (Latinoamérica) • Français • Bahasa Indonesia • Italiano (Italian) • 日本語 (Japanese) • 한국어 (Ko

Standard JS 27.8k Dec 31, 2022
🌟 JavaScript Style Guide, with linter & automatic code fixer

JavaScript Standard Style Sponsored by English • Español (Latinoamérica) • Français • Bahasa Indonesia • Italiano (Italian) • 日本語 (Japanese) • 한국어 (Ko

Standard JS 27.8k Dec 31, 2022
❤️ JavaScript/TypeScript linter (ESLint wrapper) with great defaults

JavaScript/TypeScript linter (ESLint wrapper) with great defaults Opinionated but configurable ESLint wrapper with lots of goodies included. Enforces

XO 7k Jan 9, 2023
NodeJS library develop quick start: TypeScript + CI/CD + Release Workflow + Linter + Changelog + ...

node-lib-starter Start NodeJS + TypeScript library developing with ease, have fun! Include Lint Git Hooks Release workflow CI/CD Changelog Configurati

LinbuduLab 22 Oct 28, 2022
🤪 A linter, prettier, and test suite that does everything as-simple-as-possible.

Features Fully Featured Code Grading Knowing if you need to work on your code is important- that's why we grade your code automatically. But, unlike o

Fairfield Programming Association 18 Sep 25, 2022
All-in-one code linter and formatter for TypeScript and JavaScript

Uniform is a CLI tool - code linter and formatter for JavaScript and TypeScript. Works using eslint and prettier under the hood.

Irakli Dautashvili 21 Feb 27, 2022
Linter for Nix using tree-sitter 🌳 + ❄️

Linter for Nix using tree-sitter ?? + ❄️ This is a simple linter for Nix that uses tree-sitter. I plan on extending it with more detections in the fut

Ben Siraphob 41 Dec 20, 2022
Yet another linter rule to detect compatibility of CSS features.

stylelint-browser-compat Yet another linter rule to detect compatibility of CSS features. This plugin checks if the CSS you're using is supported by t

Masahiro Miyashiro (3846masa) 16 Dec 15, 2022
Type predicate functions for checking if a value is of a specific type or asserting that it is.

As-Is Description As-Is contains two modules. Is - Type predicates for checking values are of certain types. As - Asserting values are of a certain ty

Declan Fitzpatrick 8 Feb 10, 2022
Combine type and value imports using Typescript 4.5 type modifier syntax

type-import-codemod Combines your type and value imports together into a single statement, using Typescript 4.5's type modifier syntax. Before: import

Ian VanSchooten 4 Sep 29, 2022
🧬 A type builder for pagination with prisma and type-graphql.

?? Prisma TypeGraphql Pagination Prisma TypeGraphql Pagination builds prisma pagination types for type-graphql. import { ... } from 'type-graphql'

Arthur Fiorette 2 Apr 21, 2022
🐬 A simplified implementation of TypeScript's type system written in TypeScript's type system

?? HypeScript Introduction This is a simplified implementation of TypeScript's type system that's written in TypeScript's type annotations. This means

Ronen Amiel 1.8k Dec 20, 2022
A type programming language which compiles to and interops with type-level TypeScript

Prakaar Prakaar (hindi for "type") is a type programming language which compiles to and interops with type-level TypeScript. Prakaar itself is also a

Devansh Jethmalani 17 Sep 21, 2022
A transpiler from golang's type to typescript's type for collaboration between frontend & backend.

go2type go2type.vercel.app (backup site) A typescript transpiler that convert golang's type to typescript's type. Help front-end developer to work fas

Oanakiaja 8 Sep 26, 2022
100% type-safe query builder for node-postgres :: Generated types, call any function, tree-shakable, implicit type casts, and more

⚠️ This library is currently in alpha. Contributors wanted! tusken Postgres client from a galaxy far, far away. your database is the source-of-truth f

alloc 54 Dec 29, 2022
Fast and type-safe full stack framework, for TypeScript

Fast and type-safe full stack framework, for TypeScript Why frourio ? Even if you write both the frontend and backend in TypeScript, you can't statica

frourio 1.1k Dec 26, 2022