Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I've always wondered if you could create a runtime inferrer of types for these sorts of projects. As in, attach something that observes function calls and sees over the course of some amount of time what types are passed into them, and have them make a best guess of what arguments are what types. While of course it couldn't be perfect, it could save a lot of grunt work.

I made a quick version of this idea in Python 3.4, where it was much easier since I could modify the AST on import, but I never quite got it where I wanted it and sort of lost passion.



I've wondered about this, in the context of generating skeleton Typescript definition files automatically by analysing the source of the library. It appears that Tern (http://ternjs.net/) is the most advanced project for extracting this kind of information from Javascript source files, and can be used as an editor plugin for some degree of intelligent autocompletion. You could also potentially use Esprima (http://esprima.org/doc/) to analyse the AST.

The old Visual Studio Javascript autocomplete engine apparently worked in a similar way to what you suggest, running the code in a sandbox and then analysing the types, but they've now moved to a static engine (which I think is also used in VS Code?) - some information at https://blogs.msdn.microsoft.com/visualstudio/2016/04/08/pre...


The new engine ("Salsa") is actually powered by Typescript, which is neat.


You could probably do 80% of the inference statically as well. For instance, given something like this:

  function incrX(obj) {
    obj.x += 1
  }
We can infer incrX expects an object with property x, which is probably an integer. And therefore, a call like `incrX({x: "hello"})` is probably incorrect. In fact, I think this is how type inference in languages like OCaml works.

That said, I do wish statically-typed languages generally had runtime type checking built in. For instance, I can tell Typescript what type of response we're expecting to get from an API call, but that doesn't mean the compiled Typescript will warn me if the API call ends up with a different type.


> We can infer incrX expects an object with property x, which is probably an integer. And therefore, a call like `incrX({x: "hello"})` is probably incorrect. In fact, I think this is how type inference in languages like OCaml works.

Except OCaml's typing is much stricter than JS's, in JS `obj.x += 1` is perfectly valid if `x` is a string. In fact due to all the runtime type conversion protocols you can have pretty much anything as `x` and have `obj.x += 1` succeed.

So that requires a strict break and separation with JS semantics and treating JS (or whatever) as an implementation detail and "assembly", which is the opposite of Typescript's purpose (it's more of an Elm or Purescript or ocaml_in_js thing)

> That said, I do wish statically-typed languages generally had runtime type checking built in.

Statically typed languages with lots of holes (at the type-system level) like Java or C# do have runtime checks. Those with less holes like OCaml or Haskell don't as the only way to get the "wrong" types at runtime is to have wilfully undermined the type system in which case the developer is on the hook for making sure they do that correctly.

> For instance, I can tell Typescript what type of response we're expecting to get from an API call, but that doesn't mean the compiled Typescript will warn me if the API call ends up with a different type.

That would require TypeScript having its own runtime rather than compiling to regular Javascript, or it would require that TypeScript inject a fuckton of type checks which would make the output orders of magnitude slower (both from the overhead of javascript-level type-checking and from the increase in code size and decrease in JIT optimisation opportunities).


To expand, with regard to (GHC) Haskell: you can perform run-time type checks with the Typeable typeclass, and you can forgo compile-time checks in favor of runtime checks with Data.Dynamic. You can also replace compile-time detected type errors with "if this is executed, explode", with the -fdefer-type-errors flag. And of course, in any typed language you can apply sufficiently general types that you need to perform manual checks for safety.


Typescript couldn't actually do this for interfaces. Typescript interfaces don't exist post-compilation, and the only way to check for them would be to ensure that every expected property exists on the incoming object.

This has a very annoying side effect of never being able to exclude interfaces from a union type:

    function doStuff(thing : string | SomeInterface) : void {
        if (typeof(thing) === "string") {
            // thing is still typed as string | SomeInterface,
            // because there's no guarantee that the
            // string object doesn't implement the interface.

            // If SomeInterface was a class instead of an interface,
            // then thing would only have the string type here.
        }
    }
Also, this is ignoring the fact that you would also need to check the parameter types on an incoming function, which AFAIK isn't possible at all.


I work with TypeScript fairly closely and was surprised at your example, because I was sure that this already works. It turns out the type narrowing is actually special-cased on only some particular AST. You can see it working here, where "charAt" would not be allowed if it was still |SomeInterface:

http://www.typescriptlang.org/play/#src=interface%20SomeInte...


So I started exploring this again today, and it ends up that what you had works, but if I parens on the typeof check, it no longer works:

    if (typeof(x) === "string")
I opened an issue: https://github.com/Microsoft/TypeScript/issues/9391

Thanks for the help!


I was wanting the same kind of thing! We have an old Node (lol, funny to write that) code base of about 60 services that fetch data from 3rd party APIs. They're all very dis-organized and written in different styles, so a tool like that would be really useful. I've been experimenting with using Facebook's Flow on this, but it doesn't do the magic that you describe (which I'd like)


The good thing about TS is that you can add types gradually. I actually think there's a lot of value in adding the typing manually because A) you're guaranteed to find bugs, and B) you have to revisit your assumptions with the advantage of hindsight.


With Flow you can also add types gradually. Actually, one of the reasons why Facebook created Flow is that they thought that TypeScript was not "gradual enough". A good presentation on how Flow differs from other type systems: https://www.youtube.com/watch?v=VEaDsKyDxkY


I also wonder why no one experimented on exporting the types from jitters and making preliminary type annotations from that information. Sounds very basic when I think about it but I have no idea how jitters work so maybe it's just nonsense.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: