Announcing TypeScript 2.0
blogs.msdn.microsoft.com
blogs.msdn.microsoft.com
- Simplified Declaration File (.d.ts) Acquisition (via npm)
- Non-nullable Types
- Control Flow Analyzed Types
- The readonly Modifier
Finally, I was wating for months :)
tsd install angular
is replaced by this? npm install -s @types/angularAside, my biggest concern with the new @types scope is that it is still tightly coupled with the DefinitelyTyped megarepo. DT has been a great help over the years, but it's so huge and increasingly hard to contribute to as DT has increased its quality bar and its size makes it a stress test on git tools and IDEs, too.
Otherwise, the @types packages on npm are the way to go.
Please note that most of the @types/XXX packages are just automatically extracted from the DefinitelyTyped repo. Big packages with lot's of updates can use their own repo.
But this is a huge, huge usability win. No more haggling with additional tools to get your typings.
I can see it's better (not sure why a single repository(!) was ever considered a good idea), but in the end both methods work if all you need is to obtain the latest version of a .d.ts file.
This is huge from a usability perspective.
http://www.typescriptlang.org/docs/handbook/tsconfig-json.ht...
Non-nullable types, tagged union types, and easy declaration file acquisition are definitely the biggest wins for me with this release.
Edit: I realize you mean Typescript, my apologies
Non-nullable types, OTOH, might just be the thing that makes me start using TS, despite my love of dynamic typing.
Unfortunately that's something TypeScript doesn't tackle, but you can use external libraries for floats, where you work on floats as... strings.
You knew that, but I'm just spelling it out for others.
https://github.com/roboprog/nashorn_play/blob/master/script/...
I've come to the conclusion that "mandatory and immutable" should be the default, but there are precious few languages in which that is the case, rather than some noise words that have to be plastered all over. (the noise words should be something like "dont_know_when_or_if" and "whacked_whenever_i_feel" for optional and mutable to make you cringe when you use such a local/parameter/return-value.
It's always funny (funny-sad) to read a project or a research paper that discovered "static types turned out not to catch as many errors as we thought it would".
We've made our turing tar pit, now we have to live in it :-(
... at least until we push the whole C-and-its-spawn edifice over the cliff.
Enter the XML config file... :-(
I ranted quite a bit lately about partial function application as well, but it's not appropriate for everything. But when when you're dealing with a crowd that has no idea that there are other ways of doing some things...
And partial application is never necessary. It's elegant and useful, and can save you a bit of typing, yes, but it's never needed. It's nice to be able to type:
map (+ 3) a-list
but I don't mind: (map (lambda (x) (+ x 3)) a-list)
and in most Schemes, there's a macro called cut, which means you can do this: (map (cut + <> 3) a-list)
Which is almost as nice as the first one, and works regardless of the position of the arg you want to apply.And it's no so much that the crowd doesn't know that there are other ways of doing things, it's that they reject them out of hand, because they're different.
The first line looks odd to me, since there are just 3 expressions sitting there - no parens around map and the rest of the stuff. My ignorance is showing :-(
... but I don't want to write Java <= 7 style inner classes, either. I'll likely get a bad case of COBOL-fingers.
Instead, the first line is Haskell, the best-known language to support that particular feature. I personally dislike it, but if you're demonstrating partial application, it's the language to do so.
And in case you haven't realized it yet, Java is actually the new COBOL: Verbose, ugly, and very popular in industry.
I never saw any Simula 67 until VERY recently. Hmm. So its what Borland patterned Turbo Pascal 5.5 (and beyond) after, more or less. And Eiffel, as well. But the MIS industry keeps trying to rehabilitate a portable assembler for general application programming (C, C++, Java, ???)
Don't get me wrong, as a language I will defend C to the very end (C++ and Java, not so much), but it has a specific usecase: Low-level code, or code where you absolutely need the performance. If you're not in either area, stop. You shouldn't be using C. And, of course, Rust has been eating some of C's lunch of late...
One good thing about Unix is, the creators intended for things to be stitched together as insulated building blocks, NOT to be built as monolithic C programs (at least as far as I can tell). OK, I'm really off on a tangent now. Have a nice day :-)
Can you attach a property list to a function in Scheme? If so, maybe you could make a way for properly prepared functions to have an "apply" property. (like I said, it's been a LONG time since I did Lisp)
Then again, I don't totally understand your system, so I might just have gotten it wrong...
It's marked as experimental, but has worked flawlessly for me on a moderately sized project using typescript 2.0.0@beta
> Select the Use TypeScript Service check box to get native support from the TypeScript Language Service according to the up-to-date specifications. In this case syntax and error highlighting is performed based on the annotations retrieved from the TypeScript Language Service while code completion lists contain both suggestions from the TypeScript Language Service and suggestions calculated by IntelliJ IDEA itself.
https://www.jetbrains.com/help/idea/2016.2/typescript-suppor...
Also, how much money is MS pumping into TS? A lot of OSS has one or two super-contributors that carry the project on their backs, but typescript has a small army of smart people with significant contributions.
Obviously, there are still differentiators between the projects (like TypeScript including a known set of transpilers vs. Flow delegating to Babel), but I'm curious to know if they are converging on their core feature (e.g. how to do type-checking/static analysis).
It's pretty easy to see where things are going. Advanced type systems (Elm, Scala, ML, Haskell, whatever) have the features we really need, and tooling (IDE support, etc) can use that info to provide crazy good tooling, so any type system developed in 2016 and beyond must have all of these things to be of mass appeal.
If you're referring to differences in the way TypeScript narrow types based on control flow analysis, we don't see one as being "better" than the other, but TypeScript takes a more optimistic approach to avoid putting users in frustrating scenarios where the analysis is too limited. Most users tend to prefer this to the slightly more rigid approach used in Flow, so we felt we made an ideal choice there.
If you have any specific thoughts or ideas, feel free to leave us feedback on our issue tracker.
I think the javascript type system world is still evolving, and the only "wrong" thing to do is to say "Ok, its a solved problem, let's run away with THIS ONE and kill the others".
As long as we still have at least 2 reasonably well known ones, I'm happy.
> Previously flagged as an invalid flag combination, target: es5 and 'module: es6' is now supported. This should facilitate using ES2015-based tree shakers like rollup.
So now I can add rollup to my production build pipeline to remove dead code. Nice!
Unlike most people on HN, I like JavaScript. I build web app since 2011. I liked working with jQuery, then Backbone and Grunt, then Angular and Gulp. Now I'm working with React, Webpack and Babel (ES6/ES7) and writing web apps has never been so much pleasure. JavaScript in 2016 is really fine for me. And the common point in my JS experience from 2011 to 2016 is that dynamic typing has never been a problem. I also worked with strongly typed languages for years like Java or C# and I still prefer the flexibility of JavaScript.
So it's strange because I admire TypeScript. The work accomplished by its team is really amazing. And it's so nice to see a single library reconcile developers with JavaScript. But in the other hand, I prefer keeping my JS without types because it just works fine for me and the teams with who I worked.
I have no idea how your brain works, but for me working with a non-trivial JavaScript codebase is a nightmare.
TypeScript makes web development fun again.
Every making even a small change to a JS codebase you haven't touched in a while that isn't VERY thoroughly tested? (Doesn't even need to be a big code base).
Thinks will break. And you will lose hours of time.
Static typing doesn't eliminate all bugs, of course. But it can catch many common mistakes made in JS.
But static typing catches a lot of things otherwise only caught by tests.
Also, try Haskell. Haskell code that compiles works correctly sursprisingly often. ^^
Types are inferred for the most part. Typically, you have to annotate less than a quarter to make your project fully typed. I have about 7-10 types per 100 lines in my current project and I do use "noImplicitAny" and "strictNullChecks".
Most of those types are for fields and function/method signatures. You probably might want to document those types either way. Type annotations are a lot nicer for this than JSDoc comments.
I also don't think JS is the root of all evil, and I use Emacs rather than an IDE (although we do have really good integration with regular JS, in the form of the famous js2-mode, and flycheck's linter integration). I, mean, do you really need your IDE checking your types as you type? It's not that slow, and us Emacs users have M-x compile, so we can run our code, and than jump back to the problematic line when an error occurs, and I know IDEs have similar functionality.
Don't get me wrong: static typing can be good at times, and option static typing and compile-time type analysis are useful tools, and I'm glad TS, Flow, and the like exist. But I always see a flock of comments saying that they couldn't possible live without static types, and thanking TS for taking them out of the hell of dynamism, and wishing there was something similar in Ruby/Python/whatever.
I don't really get that.
If a colleague writes a function/method that returns something, in JS, how do I know what it is? I have to read the function or its tests. With a statically typed language I immediately know the structure of the returned "thing" (don't want to say object) and can infer how to work on it.
BTW, with IntelliJ and its debug mode for Java we almost have some sort of weird REPL. By pressing Alt+F8 one can, during a breakpoint evaluate an arbitrary Java expression while accessing the values in scope. I use it a lot, despite having my types.
And I do a lot of Lisp programming in Emacs, where the support for REPLs and livecoding is ungodly. Really, really good.
I'm constantly looking at the source even with static types. Unless you're having a Haskell-like type-system the function's signature will still miss most of what the function is actually doing.
How do I know if a function does a network call? Saves a file? Changes the DOM? These are really important things to know when calling code and the type-system is completely oblivious about them.
What I usually see however is that projects using static types frequently have at least twice the team size as the equivalent projects using dynamic types. Communication overhead follows, ownership fades and debt creeps in quickly. After a few month they usually have no traces of agility left.
For me, a lot of the Spring classes are designed very well. When working with them I don't often need to look into the source code. Very often just looking at the methods (by using autocompletion) is enough.
Not taking these details into account will be the source of most bugs :)
I would never have been able to integrate netty into our game servers that optimally with only the docs as reference for one. Yet its documentation is really, really good. I still wanted to know its internals in order to hit the fast paths.
Whether you're using static or dynamic types, the very same holds true to build robust software: understand what you're doing.
Managing complexity and reducing state will always be the biggest factors to quality, regardless or type systems.
It's ultimately a matter of preference, though.
No, it's the fact that it's effectively the new COBOL.
Yes, I'll go have that talk with H/R now...
It returns Promise<T>
> Changes the DOM?
It doesn't. React does that. ;)
Basically, TypeScript + React + a mostly purely functional style with a sprinkle of side-effecting IO is a really, really good combination.
Also, I find the argument a bit silly. "This cycling helmet doesn't protect your knees and elbows and spine, so its completely useless and you can remove it!"
You can see that here: https://facebook.github.io/react/docs/pure-render-mixin.html
"IF your React component's render function is "pure""
nothing stops you from writing impure rendering functions. You can delete and manipulate elements at will.
For some reason, everyone always likes dealing with absolutes. Thats not how things work
* "Tests wont exhaustively check everything!"
Yes but they exercise the common cases, and the cases where the code will trip-up in real use are rare if the code is decently covered with tests.
Yes, its still possible to encounter edge cases. If it looks like that might be the case, add fuzz testing and property testing too. Pick the tool.
* "Types wont detect all errors!" -
Yes but detecting some errors is still useful. They mostly track dependencies between parts of the codebase: they determine how modules talk to eachother. This is useful, especially when I'm reorganizing code.
Also, its exactly where unit test fail to help, due to mocks: if I change module M, i don't know whether its dependencies are affected or not without looking at all of them and checking their mocks of module M. The situation gets even worse for second-level dependencies, and so on.
* "Unsound type systems are useless!" - No they are not. Not if its possible to isolate unsound usage and "hand-prove" it by carefully checking it. There is still value there: you can write things that the type system doesn't know are sound and hand-check them (by paying with more effort), or you can write things that it does know are sound, and enjoy the type system's ability to help you avoid errors.
* "Soundness isn't very important" - It depends. Is this unsoundness pervasive, like the null/undefined unsoundness? Maybe its useful to fix it then.
There are no absolutes.
If you weren't supposed to do it they wouldn't give you functions to do it.
I'm not 'dealing in absolutes' I'm applying the definition of pure to what React is, and it isn't pure.
The rest of your post I don't follow, you're just talking to yourself, I haven't made any of these claims.
With the browser DOM model, end-users perform the DOM mutations. This generally means that they must keep the application state in sync with the DOM state, manually.
React's VDOM model encourages pure render functions, since a new VDOM is constructed every time and mutations are performed by React itself.
Also, nothing stops you from writing impure functions in PureScript either. You could define FFI functions that claim to be pure but aren't. I guess PureScript isn't pure then? Oh, and Haskell isn't pure due to unsafePerformIO. So nothing is absolutely pure; the question is what style is generally encouraged by the design of the framework/language, and to what degree. (there are no absolutes)
And PureRenderMixin isn't default because it does a shallow reference comparison on props/state, which only works reliably for immutable data structures. If all JS datastructures were immutable, it would've been used everywhere. However thats unrelated to whether `render` is pure.
That still doesn't say anything; is the action referentially transparent? is that a delay? a network call? All a Promise tells me is that the result will come at a later point in time.
> It doesn't. React does that. ;)
My point was about side-effects and complexity in general which the static type-system is generally very clueless about. React is a runtime and dynamic solution to that problem; types aren't really useful here :)
Besides, you're most likely using React with Immutable.js and having some pattern like Redux on top. Which is basically choosing immutability and hostility to state over static types :)
> "This cycling helmet doesn't protect your knees and elbows and spine, so its completely useless and you can remove it!"
That's not what I meant, its more like "why wear winter clothes in the summer?"
It's easy to read code you wrote yourself 5 minutes ago, try again in 6 months.
You can't hold more than ~7 things at once in your head; once things are that simple you can see bugs a mile away, types or not.
The inverse is not true; types won't help you juggle 15 things at once and bugs will happily slide through the cracks. You're going to forget your codebase, types or not, and when you come back to it only simplicity will help you quickly figure out what you were doing with it.
For example: if you implement a store that only sells electronic books will have a lot of assumptions regarding the selling and delivery process. Later the business wants to start selling physical things and needs to handle stuff like shipping costs, tracking and so on.
For problems like online stores, the possible directions in which they can develop are well understood and its easier to plan ahead. For most other things, its not, and the ability to reorganise code to be usable in different ways is invaluable.
Promise<T> is like Haskell's IO<T> in terms of what it says. In short, "anything goes"
> My point was about side-effects and complexity in general which the static type-system is generally very clueless about. React is a runtime and dynamic solution to that problem; types aren't really useful here
> Besides, you're most likely using React with Immutable.js and having some pattern like Redux on top. Which is basically choosing immutability and hostility to state over static types :)
Why is everyone always making it an "either or" thing? The usefulness of types is in them describing the input/output dependencies in your code. Change the nature of your inputs, and it tells you what dependencies, or dependencies of dependencies (etc) will be affected. Change the nature of your output, and you get the same for your dependants. This is mainly what TypeScript gives you: it tells you how your modules are connected.
Immutability wont help you with the above. If in the return result of the exported function `f` from module `A`, I change this attribute from "firstName" to "name", who will be affected? TypeScript can tell you things like: `A.f` is called by `g` from module B, which then passes the data unmodified to `C.h` which then tries to access the `firstName` attribute. Voila, now you know. Now, how will immutability, hostility to state or unit testing help you with this question?
I agree, but I find types way too weak in that respect. Its not enough to know a function accepts ints; I want to know its range as well.
I spent so many weeks hunting down overflow and out-of-range errors and null pointer exceptions that types feel like an illusion of robustness at best.
> Now, how will immutability, hostility to state or unit testing help you with this question?
Not that much, I'll give you that. But the same is true for a function whose range was 1-20 being refactored into a range of 1-10; types won't catch that.
I used to like types, then testing, now I'm looking at specifications I can write once, compose and then generate assertions, documentation, test data and everything else from. Its by far the best ROI of the three.
Types actually help with this too. Instead of changing the possible range of a thing, change its name too: the compiler will quickly let you know of all the places that depend on it. Now you know what to check.
Typically you have a set of standards for how things get returned. 'isSomething()' returns boolean, 'getSomething()' returns an object, 'getSomethingClassName()' gets a model representing that, etc.
Overall it's really the same as static: you usually have something in the function definition that makes it intuitive what it returns. The fallback is documentation directly above the function's implementation that should describe it.
When you run into the "well what does the object contain that gets returned?" situation then dynamic and static have the same issue: you have to go to the definition to get that information.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
http://es6-features.org/#Proxying
Otherwise, yeah, I can hardly make heads or tails of most "self documenting" (i.e. - undocumented, per SOP) static typed code.
You confuse my statement. I was not referring to things that should be meant as synchronous properties. These are methods that do more like make an AJAX call to a server. Those that return promises or take in callbacks would be awkward or impossible to force into a property or proxy.
I was merely referring to the act of making code as obvious as possible for its intended outcome.
Anything but the most trivial program will still require you to investigate. Once you're familiar with a piece of code you can start making assumptions, and the types get you a little closer to that a little faster.
I've worked on multi million line mono-repo pure javascript with zero tests with hundreds of devs working on it, and it worked fine (in fact, we were moving more stuff from the Java/C# code into JavaScript to reduce overhead and friction). If you have tests on top, or if your devs are actually good, its just easier/better.
Now, I'm not saying a proper type system doesn't add value. Thats a whole different argument. But any team who can build good software in a static type language can do so in a dynamic one. Its just a different set of tradeoffs.
And aside for strict sound type systems, you need (almost) t he exact same amount of unit tests either way. If you don't have tests you're not writing good software either way.
You're throwing out (or, rather considering the tricks you can pull in Typescript, hugely reducing) entire classes of issues when using a simple type system.
> I've worked on multi million line mono-repo pure javascript with zero tests with hundreds of devs working on it, and it worked fine (in fact, we were moving more stuff from the Java/C# code into JavaScript to reduce overhead and friction). If you have tests on top, or if your devs are actually good, its just easier/better.
I've worked on a huge PHP codebase once, with 10 developers working on it and no tests. I would have given somebody else's right hand to have a type system back then.
> Now, I'm not saying a proper type system doesn't add value. Thats a whole different argument. But any team who can build good software in a static type language can do so in a dynamic one. Its just a different set of tradeoffs.
The point is, the cost of adopting Typescript is frankly, very low, from my point of view, considering the huge benefits it has over raw JS, it's all win.
Example: you have a function that takes a 'file' parameter, and you need to modify the function, so you need to know what the properties on the file object are. Is it some custom File class, or just a poor name choice, or the browser File interface?
In a statically typed language it would be marked explicitly and I could probably just CMD+click on it in my IDE and be done.
In, e.g., javascript what recourse do I have? No 'File' module is explicitly imported, and the function is invoked somewhere in library code so I never see the file object constructed. So, let's say it turns out to be this 'File': https://developer.mozilla.org/en-US/docs/Web/API/File —how do I discover this? So far it's been time-wasting, unsystematic trial-and-error sorts of things.
It's not as big a deal as I thought when first switching to JS—but if you believe writing readable code is important, you're lose a major tool without being able to label types.
- Refactoring. Refactoring a large JavaScript codebase (> 100k loc) is nearly impossible and at best incredibly painful, error prone and time consuming. With static types, it becomes a trivial and straightforward process.
- Your code is now more discoverable. You can easily find definitons, and discovering all methods and properties on an object is as simple as triggering an autocomplete pop up.
- Code is now more readable. Objects are never opaque. You never have to dig through multiple calls just to see what the shape of an object is. It's all right there.
For me, the killer app is refactoring. Writing huge amounts of JS is very painful to me because I refactor almost constantly as I add more code. Most dynamic languages have this problem. Static typing changes that completely.
Static types won't help you refactor a monster class into a structure of arrays. It won't refactor your callback hell into coroutines. It won't refactor your "one-at-a-time" algorithm into batches. Yet these all yield more agility and performance.
The thing is, I usually have so much less code when throwing static types out the window that refactorings become a non-issue. I get away with basic Emacs macros and unix tools.
Find: <old name>
Replace: <new name>
…continue working.
It's quite impressive what VisualStudio + Resharper + plugins or IntelliJ with a few plugins can do in their respective first class languages.
Back when I did C# last year I was doing 2D skeletal animations in Unity3D and pretty much wrote the most non-idiomatic C# code ever. Everything was bitfields, structures of arrays and integer indices into contiguous memory buffers rather than heap references.
The tooling was completely useless there. You can't optimize for cache misses and branch predictions without throwing all that nice typed goodness out the window.
As much as types, tests and whatnot can help you, at the end of the day it is impossible to do engineering without understanding what you're doing, regardless of what is there to do heavylifting for you.
You can, of course, try using case-sensitivity and whole-word search modifiers while trying to maintain naming conventions to keep replace-all working a little longer, but that's just an incomplete and buggy attempt at creating your own watered-down type system, not proving that types aren't useful.
First, the trivial ones are great and useful refactorings too -- and still difficult in dynamic type systems.
Second, static types also benefit the more difficult refactorings that you still have to do manually, by giving you compiler errors and warnings when you botched them at least at the type level. With dynamic languages those need to be done both 100% manual and with no aid.
Third, static languages are a superset of dynamic typed languages, so they can do everything the latter can do, while the inverse is not true.
You can have a "var" or "variant" etc type in a dynamic language that lets you code exactly like in a dynamic typed language where you want it.
(In fact dynamic typed languages are just static type languages with a single type: https://existentialtype.wordpress.com/2011/03/19/dynamic-lan... ).
You can specify the domain of values with types, but not their ranges. Side-effects fall through unaffected by types as well.
I've done plenty of refactorings in huge statically typed codebases; types are a very, very superficial help there. Everything compiles fine but now you're passing 20 to a function whose range is 1-10. Or you're now generating the wrong filenames.
To me the overhead of using types outweighs the advantages they bring to the table. If I can help it I'd even choose to have a spec I can enforce at runtime using custom predicates than some vague predefined types with weak semantics or unit tests I have to maintain manually.
They aren't mutually exclusive. I'd rather have both.
I do want types when building native software, because these sit directly on the CPU and have to match the hardware. Other than that I feel they at best give you the illusion of robustness - unless the type-system is actually sound but very, very few are.
What good is having a int type if you can't limit its range?
I'm not going to maintain BOTH static types and tests. The ROI is way too low on that and won't even come close to guarantee robustness.
Assertions over composable predicates gives me much more out of the time invested to write it. They are right there in the code at runtime, not separate like unit tests or in a different phase like static types.
Well then you don't have to test what happens when someone passes a string, an object, or a boolean. Most dynamic languages will silently convert many of these values into an int and produce incorrect results.
> I'm not going to maintain BOTH static types and tests.
You have to maintain documentation and you have to maintain tests and you have to maintain assertions for the implied types of your functions anyway so you might as well make them explicit in the code.
That's useless, I still need to test the value's range which implicitly checks the type.
> You have to maintain documentation and you have to maintain tests and you have to maintain assertions
Not if I can generate most of it from the specification data.
Most types in the program aren't ints anyway; they're interfaces. If I want to have a range-limited value, I could just create a new type for it.
In what sense?
With type inference you don't have to manually specify them.
With a variant type, you don't have to confirm to a specific type, but can accept all, if you want it.
And you still need to conform to an interface in a dynamic language, if your function is x.indexOf(x) you still need to make sure to use it on two strings, if it's a math function on some numbers (and depending on the function, on a range), etc (1). So you are not even spared that -- instead, you just lose the help from the compiler when it comes to it.
(1) You could e.g. let a numeric type string autocoerce of course, but auto-coercion can also happen in static languages, is orthogonal to static vs dynamic typing, and is also generally to be avoided).
I think this is true to a certain extent, but with a language like JS, there is a lot more composition of generics than there is inheritance. I see:
add5toStuff<T extends {stuff: number}>(item: T): T;
drastically more than: class X {}
class Y extends X {}
class Z extends Y {}
The latter is always a nightmare of fighting the compiler. The former is a breeze to deal with. Your type casting will be limited almost completely to IO.The vast majority of typed web codebases I've seen were exercises in Java Enterprise development of various degrees. Generics or not the time spent typing everything is not matched by the advantages of static typing.
You'd get more robustness by managing complexity and state; I've spent far more time hunting down bugs that passed through the type-system and tests than fixing typos in dynamically typed languages.
> You'd get more robustness by managing complexity and state;
The top function has a return value of T. That's not encouraging mutability. It's only mutable because JS pass by reference, which is irrelevant to static/dynamic. If you use the return value instead of the passed value, it's "effectively" immutable and is a great way of managing state.
Having a no-overhead Filename type would make this impossible.
Types can't check the ranges of their values in most languages. And definitely can't do so at runtime.
I agree that the type systems in most mainstream languages fall somewhere short of awesome. I was putting together a small web app in Elm last week, and it was nice to work with a type system that felt like it was helping me design and write better code. That, plus it has the most helpful errors message I've ever seen from a compiler.
Heck then I can even fix the statically typed tests that might be broken.
As I wrote, static type systems are a superset of dynamic type systems. So they can have both.
Besides, static types are, among other things, automated tests for the trivial stuff -- which the computer automatically tests/ensures them instead of a human writing them as busywork (and potentially getting them wrong).
The "sound" type system requirement doesn't make sense either. A non sound type system can still catch the majority of parameter/variable misuses automatically. With dynamic type systems you don't even have that, so essentially what you wrote means "I want it all or nothing". Cool when it comes to personal ambition, doesn't make sense when what you get still protects you from all kinds of errors and helps you refactor and self-document your code.
>I've done plenty of refactorings in huge statically typed codebases; types are a very, very superficial help there. Everything compiles fine but now you're passing 20 to a function whose range is 1-10. Or you're now generating the wrong filenames.
That would matter if static types somehow prevented unit/functional testing, which they do not.
And, depending on the language, the help of static types can be far from superficial. Even in Ada, back in the 80s, you could define the 1-10 range as a constrain on the type/input parameter.
Yeah, they don't catch all problems -- but that's good too, else we would not have jobs.
Given how mediocre the average software out there is, I'd much much rather have an industry focus on actual engineering. Its a lot more profitable to find new problems to solve rather than continuously fix your own mess.
I used to write very well documented statically typed code, and then watching people without domain knowledge butcher the hell out of it after I left.
At the end of the day knowing what you're doing is priceless. Just like having guard rails is no excuse to not learn how to drive.
Alls I'm saying is that types are very overrated when it comes to actual robustness and correctness. You can get it without types and you can miss it with types.
These alone are already huge. Think about it for a while, keeping a code base healthy as it goes through evolutions involves a lot of renaming and moving things around.
But there are so many more refactorings that are tedious or even dangerous to do manually. For example, switching the parameters of a method, lifting a method in a base class, extracting an interface out of a class and using that interface everywhere in your code base instead of the concrete class, etc...
Spend some time reading the extremely long list of refactorings offered by IDEA and Eclipse, it will open your eyes.
This is almost certainly our difference. The utility of static typing is greatly diminished when the codebase is not very large.
> Static types won't help you refactor a monster class into a structure of arrays.
Sure they will. I mean, sure, it won't be a one-click magic refactor, but that was never the benefit anyways. One strong advantage of static typings is that now you'll know exactly when all your call sites break, so that finding and fixing them will be much more straightforward.
Fallacies! I'd have said "lies" but I realize you just have limited information. See below.
- Refactoring. Refactoring a large JavaScript codebase (> 100k loc) is nearly impossible
Really? Refactoring large codebases in VisualWorks Smalltalk was a joy! Hyper nimble. If you stuck to canned refactorings, you had 100% confidence. For years, we were talking about how we could refactor an order of magnitude faster than other environments, and this is still true. - Your code is now more discoverable. You can easily find definitons, and discovering all methods and properties
Discovery in Smalltalk was much superior and way more nimble. Combining senders/implementors searches, syntactic pattern matching, and runtime discovery was powerful and joyful to use. - Code is now more readable. Objects are never opaque. You never have to dig through multiple calls
I don't know what you're getting at here. No environment has been more transparent to work in than Smalltalk. You don't just get to read a spec of the object -- you actually get to see it and poke and prod the live version of it to verify your understanding and test your theories. (I understand you can do this in languages like C++ -- it's what I use in my day job -- but it's literally an order of magnitude nimbler in Smalltalk.)What you have to say about dynamic languages perhaps has to do with somewhat ad-hoc language design combined with somewhat ad-hoc design of the environment and distribution/execution platform. (Javascript/Web browsers?) It certainly doesn't have to be true for dynamic environments per se.
But yeah, probably not.
Well, you have very detailed trees, anyway. But the forest is often quite obscured: http://stackoverflow.com/questions/39672359/make-all-identif...
Yeah, I know I'm complaining about one of the worst offenders, rather than TypeScript, but "Welcome to My Nightmare", as it were.
The whole "lets use classes in JavaScript" movement makes me very sad. Its as if today's web developers are now rediscovering the 90's and all the mistakes that were made back when OOP was the new shiny thing.
I get WAY more annoyed fighting with TypeScript's type-system than fixing the rare runtime type error, which is usually trivial to find anyways. This all feels like a very superficial and inefficient way to achieve correctness.
The real hard to find bugs come from state and complexity, both of which are completely ignored by static type systems. Instead I see the exact opposite: the new shiny typed abstractions introduce so much state and complexity that any advantage gained by having static types is lost there.
I probably sound very pessimistic here; the older I grow the more I appreciate Alan Kay's quote about the internet and the web for being so damn spot-on.
The computer industry is the only industry that is more fashion-driven than women's fashion. -- Larry Ellison
These cycles come and go. Sometimes static typing is hot, sometimes dynamic typing is hot. Best bet for pragmatic people is to figure out what works for you and run with it.The TypeScript compiler (which is written in TS) itself uses zero classes. There's no need to use classes to get static typing. If you're writing TS the "right way", you write the JavaScript you would have written anyway, and add type annotations to create contracts and descriptions of behavior.
So of course, when you give TypeScript to someone who doesn't have a strong "normal" JavaScript background, they'll jump straight in what they are comfortable with and go full enterprise Java on it.
Note that even vanilla ES6 had this problem, just to a lesser extent. All languages have shit like that... JavaScript itself does (we're just used to "the good parts" after so many years, but it took a long time.
The fact TypeScript provides some of those construct doesnt mean we need to use it, but it means less experienced teams will.
I'll never join a company that uses TypeScript unless I get to see the code base first.
That seems reasonable. But wouldn't the same thing apply to Javascript? Terrible Javascript code bases are very common.
For this particular stuff, if a team is really into the whole OOP/classes things, it's not like a small feature like arrow functions vs not, or semi-colon vs not... it will dictate the entire architecture of the entire code base, and it's easy to detect, so why not?
It has some very un-C# like features: https://www.typescriptlang.org/docs/handbook/advanced-types....
I am always surprised when people in JS-land say they don't like types when every major framework then goes on to recreate 80% of the framework of types rather than work in a truly prototype-oriented world.
> I'll never join a company that uses TypeScript unless I get to see the code base first.
Given the way those sorts of things work, you're basically saying you don't want to work with typescript because someone might use a feature you feel uncomfortable with. That's good to get out of the way up front, but it also projects the image you have a huge chip on your shoulder and assume everyone else is an idiot who doesn't understand things as well as you do.
Wouldn't you like to work at a place where you discover something new? I am sick to death of being the subject matter expert, myself.
And for your second point, I love to learn something new! But that is specifically something I've had to deal with far too many times already (not just with TypeScript), so it wouldn't be new. And it is quite common these days for companies to show you their code when they get near offer time, or to discuss their architecture and coding philosophy, so I very rarely have surprises on that front anymore. Doesn't mean I don't learn new things. I don't avoid things that haven't burnt me yet. Heck, even if they did, it might be because I didn't do it right. But there's only so many times I can get burnt before I start avoiding certain things :)
I don't mean to press this point too hard, but you feel comfortable offering a dissuasive opinion on something but not "talking about it"? I don't know how to interpret that.
> But that is specifically something I've had to deal with far too many times already (not just with TypeScript), so it wouldn't be new.
I don't know what you mean by this either, I'm sorry.
> And it is quite common these days for companies to show you their code when they get near offer time, or to discuss their architecture and coding philosophy, so I very rarely have surprises on that front anymore.
I certainly think the second half of this is true. I think it's quite rare for companies to actually share real production code in any significant volume, unless of course it's already in the open.
> But there's only so many times I can get burnt before I start avoiding certain things :)
Again... what do you mean? Are you implying that Javascript has burnt you? Or Typescript? Or you won't use technology funded by Microsoft?
I'm sorry, I read your post several times trying to understand your intent, but I ended up with more questions than I started with. That's probably on me.
https://github.com/ReactiveX/rxjs/blob/master/src/Observable...
But they also use the pipeline operator (::) to chain together methods in a way that's effectively functional.
I just think jeremiep is conflating static typing with Java-style OOP and "design patterns".
However, they do provide some syntactic sugar for OOP, which is useful if you have a JS codebase that is using OOP, because if nothing else, it provides a standardized method of creating objects and classes.
Unfortunately, because most devs are comfortable only with OOP and since typescript is amongst the easiest ways to do OOP in JS, a lot of Typescript code in the wild tends to be OOP heavy.
A little common sense goes a long way.
That's just not true. If you model your state and its transitions as types, then it's entirely the case that your type system can help you out. It can also force you to write down an explicit & precise guide to said system, which will help readers.
> The real hard to find bugs come from state and complexity,
No one argues that this is the case, but what's key to understand is that people still make the stupid mistakes. People like you and me. I've got over a decade of experience, I've shipped code in common lisp, javascript, ruby, python... you name it in the who's-who' of dynamic languages and odds are I've shipped code in it. And I can STILL make silly little type errors.
I'm tired of this collective fiction that we're all so awesome that we don't make those errors. Removing those is important. It lets me think more about the interesting parts of the code and trust the computer to do the tedious bits for me. That's what automation is all about, isn't it?
That alone makes TypeScript worth the trouble IMHO.
Only if the library itself is written in Typescript or the ambient definitions are perfect. Not necessarily a detractor from the language, but still a practical time sink given the current state of external typings. It's definitely getting better, but it's still quite far from a minimal nuisance.
What could possibly go wrong?
This is of course less ridiculous if some documentation about each routine is displayed as you up and down arrow through the choices.
Personally, I like types because entire classes of errors and bugs no longer apply without me having to think.
Because JITs do type inference and compile specialized code with an assumption type doesn't change, they stop working when type(s) change(s) dynamically. When that happens, JITs need to deoptimize code, which leads to a dramatic slowdown.
In other words, changing type is the case where JITs don't help and their performance nosedives, because it breaks the underlying assumptions on type stability. Type stability is needed to generate compiled binary (x86, ARM, etc.) code.
The code running under a JIT will behave like the static typed code when the code (and data) allows it while the programmer didn't have the additional burden of doing the type analysis for the computer.
You may be confusing dynamic typing with weak types.
Also, it's perfectly fine for the JIT to generate multiple code paths that are invoked depending on runtime types even when the source code declares a single one that acts on multiple types.
(Although that's usually C code, so that might have something to do with it)
/me taps your shoulder.
Unless you wrote the code yourself you pretty much have to run the program first and then REPL to see what the type actually is and the properties it exposes Slow, arduous, unnecessary.
Also especially in the early stages of any development project I am refactoring like crazy as things come together. Static typing enables refactoring operations that are lightning fast with almost zero chance of error. Refactoring in any dynamic language is super error prone and leaves open the possibility for bugs that often show up unexpectedly at runtime.
Do people who prefer dynamic languages actually use the benefits of dynamic typing in the first place? Changing variables from one type to another mid-stream. Dynamically adding properties to objects, using == instead of === etc.. Those things are a recipe for bugs, inconsistency, and unmaintainability right from the get go.
Static typing doesn't feel intrusive, it feels like a flashlight. I don't like coding in the dark, feeling around for what everything is or is not.
If the code is well written, then no, to seeing what the type actually is. In a good environment like you have in many Smalltalks, you should be able to compose some implementors searches, then quickly know what you're dealing with. Then you quickly and easily debug the system just to be rigorous. In environments set up by smart people, these actions can be surprisingly quick and easy. (In the same way that git allows for using certain information much more quickly, quantity can become a different quality.)
Do people who prefer dynamic languages actually use the benefits of dynamic typing in the first place? Changing variables from one type to another mid-stream. Dynamically adding properties to objects, using == instead of === etc.. Those things are a recipe for bugs, inconsistency, and unmaintainability right from the get go.
None of those things are the benefits of a dynamic language, except maybe as super debugging tricks. No one who really knows how to write in a dynamic language puts stuff like that in typical code! That you say this makes me think you don't know what you're talking about, or your main exposure to dynamic langs has been through the code of yahoos.
In a good environment like you have in many Smalltalks...
No one who really knows how to write in a dynamic language puts stuff like that in typical code
That's the problem. You're talking about some hypothetical, Smalltalk environment, where some expert dynamic language programmers always do "the right thing".
The whole point is not to have to do this stuff manually, which is very error prone. Ad-hoc REPL work, and tests are very likely to have missed something.
If a REPL and tests make you powerful, then a type system that doesn't drag you down and good tooling around that will only make you more powerful.
OTOH, if you don't have plugins for things like Struts or Spring (faking the desperately needed dynamicism in config files), good luck safely refactoring your "static" typed Java (2). But once have "trained" your IDE where to look, you are back in business again.
1: it's easier to refactor JS if you restrict the scope of identifiers, of course. For starters, this means NOT naively making every function and variable in the global namespace and/or scattered in inline <script> fragments.
2: many other languages dragged into these discussions since there is some general philosophy of compile time vs runtime types discussed on this page.
No, I'm talking about a place I've worked, certain subsets of code in other places I've worked, code at customer's shops, and most of the standard library of Smalltalk.
True, I've also seen what can go wrong in Smalltalk. But in my experience, this isn't worse than what can go wrong in other languages, dynamic and static.
Since in SDLC maintenance is like 80%, and most of the time code isn't written amazingly, it seems pragmatic to have static typing.
I love Dynamic languages as much as the next guy (Ruby and clojure are pretty great in my book) but in my career, I get my guys to write in statically typed languages.
Not so much readability. That comes mostly from good naming in Smalltalk, and thinking about, "What if I had to understand this through senders/implementors searches?" However, in my experience, it helps maintainability. In general, I didn't need type annotations to help me understand the system. Good Smalltalk is about message passing, so you understood the system through who sends what to whom. What I did experience a lack of, were 100% ironclad guarantees in a couple of instances where we needed to be 100% sure about something.
And yes, it is pragmatic to have static typing for the long term!
But yeah, shoving a flag onto an object where there was no such flag can come in handy at times, if you're treating your objects as dicts or whatever (in JS). If you're doing Real OO, you'd want to put the flag into the class/prototype declaration, so that it's documented, but if you're not, or just need to attach some extra data to, say, a function, it's handy.
Also, in a well documented system, functions should note what types they except, even if it is just "any types that respond to these messages" in smalltalk, or your local equivalent.
Ugh, no. I really don't want to be looking at code where properties appear after initialization and you have reason about when the damn thing is actually available, thank you.
> Also, in a well documented system, functions should note what types they except, even if it is just "any types that respond to these messages" in smalltalk, or your local equivalent
So, like specifying type signatures in Typescript, except probably out of sync because it's not automatically enforced?
And if you're using the properties everywhere, yeah, define them, but if you need to extend an object, and the extension will only be used locally, than it's useful.
Yes, they don't have the refactoring toolkit Smalltalk does, and they can be slow, but don't discount them off the bat. The two ends of the scale are closer together than you think.
It's a tradeoff, and I didn't choose the refactoring side. Although refactoring did originate in Smalltalk...
http://www.martinfowler.com/articles/rubyAtThoughtWorks.html
With the == vs === thing, I think you're confusing dynamic typing with weak typing. Weak typing is why == and === exist, and it totally sucks.
>I'm looking at a function parameter in a random file. How do I even begin to work with it?
First off, Duck Typing: The type of the parameter is the intersection of the types the functions it is called with contain.
Secondly, this is why you document your code and choose prescriptive variable names. Honestly, this is pretty bad even with types (the first question I had when I looked at my first chunk of real world C was, "what the hell is the variable 'int rv;', and what's it being used for?).
Even I'll admit that type annotations can be useful sometimes, but I don't need them.
Duck typing (or checking types at runtime) is verbose and forces you to handle type mismatches at runtime. Which means you will probably end up throwing an error anyways when types end up missing the properties you expected.
If your code relies on properties added dynamically that might be useful for you, but god help anyone working with your code.
That's not exactly what Duck Typing is, but that is possibly true. However, in an OO system, Duck Typing has massive benefits, as you don't have to depend on inheritance to see if an object can be passed to a function: polymorphism. This is the sort of thing Java's interfaces do, albeit clumsily.
>If your code relies on properties added dynamically that might be useful for you, but god help anyone working with your code.
Obviously, you have to be careful about it. But if you're marking nodes on a graph, or attaching metadata to a function, especially if it's temporary, it comes in handy.
function useAsString(foo: {asString: () => string}) {
...
}
Note that the type we give for foo here is an anonymous type (though this would also work with an explicitly named type).And now you can do this:
interface SomeInterface {
name: string;
asString: () => string;
}
let bob: SomeInterface = { name: "Bob", asString: () => "Bob" };
useAsString(bob);
And this works, because the interface SomeInterface has an asString() method. No inheritance in sight.Because if it's not, than it's not duck typing, is it?
Not bad.
Is there a way to cast something anonymous, just a value read in from JSON, to such an interface? This would allow you to specify an important subset of things that an object needs to do, verify it in one place, then pass around the interface handle to anything that needed the underlying object in that role. Presumably, if the incoming object lacked the desired attributes, the "cast" would blow up sooner, during the assignment, rather than later, when the interface alias was used.
I don't think people use dynamic languages for that ability. It's more for the ability to not have to explicitly think about types -- it's more natural that way.
I think you are mixing some things there. The biggest advantage of dynamic typing is that it has no restrictions to how you are allowed to program. There are many cool language features that you can only use in a static language if its type system was designed to support it while in a dynamic language you can just implement it yourself (just hope it doesn't crash at runtime). For example, datatype-generic functions, object orientation (in all different variations), encoding JSON, etc.
Changing variables from one type to the other mid stream is usually a bad programming practice, so don't do that. Same thing for "==", although sometimes coercions really are convenient (for example wen you read data from an input field its often in string format).
Dynamically adding properties to objects is very useful if you are doing some "metaprogramming" stuff. For example, its trivial to write a "clone" method in Javascript because you can dynamically set properties. In a static language you would need language support for this.
> Static typing doesn't feel intrusive, it feels like a flashlight.
Which is why the Typescript project exists! When your programs are super small (for example, an inline onclick event handler) then dynamic typing wins because its concise (no type annotations), conceptually simple (no type system, type inference, etc) and doesn't get in the way. However, if you have a large program that can't fit all in your head at once then the types help a lot.
I think this is true of statically typed languages as well, at least with anything larger than a single function.
Then one day the type declarations are not, and you have to define "JSON schemas" or some such thing for other people's glop that you just want to shovel over a fence without concern of what is in it for most of the code.
That's my nightmare, anyway.
There are plenty of things that bug me more than "intellisense" (auto-completion) not working. Although type inference in my IDE on JS actually works well most of the time. (and I get to skip transpiling and source maps)
YMMV, but if you want to understand how some of "The Other Side" feels, there you go.
So why is Flow better? Have you used Typescript and Flow recently and done a comparison?
> But I always see a flock of comments saying that they couldn't possible live without static types, and thanking TS for taking them out of the hell of dynamism, and wishing there was something similar in Ruby/Python/whatever. > I don't really get that.
Because we're really tired of writing the same errors over and over. If it's just me, I can burn through a bunch of clojure code and I'm fine. But the instant I and someone else start to collaborate, subtle problems start to creep in.
What's more, so much of my job these days is about serialization, deserialization, data validation, and error handling. None of my customers have any patience for buggy software and sites. And quite frankly, they shouldn't be.
Static typing just makes these tasks easier. It makes them easier because it reminds you when forget. It forces you to think about every edge case that it's aware of, and it forces you to say something you mean and if you change that opinion, you need to make sure the code reflects that change.
You talk about static typing like Java and C++ are your experience. Using Typescript (or flow) or a modern FP like Typed Racket, Ocaml, F# or Haskell where the type systems enable new means of expressing yourself is wonderful and refreshing, to me.
The reason I like Flow better is that it's better integrated into the rest of the JS/Babel ecosystem, so it gets out of your way to a greater degree than TS when you're either not using it or want JS ecosystem integration with JSX/whatever.
I mean, sure. In that when you use typescript you probably don't need/want Babel, as most of the ES6 features you want are part of TS already.
> JS ecosystem integration with JSX/whatever.
Typescript supports both react and non-react JSX natively, so perhaps this isn't a pain point anymore?
Also: you get types. Good types are great.
What about all the tools that work with babel, rather than TS?
And from what I saw, Flow has a type system at least as good as TS's. Am I wrong?
Why not watch http://channel9.msdn.com/Events/Build/2016/B881 and tell me what you think. It sounds to me like they're dedicated not only to being on that, but to be part of the conversation going forward.
They're already taking the well-formed parts of the next 2 iterations of JS, and adding types on top.
> And from what I saw, Flow has a type system at least as good as TS's. Am I wrong?
Flow has a type system that is "as good" at troubleshooting errors within the existing javascript ecosystem, as I read it. And that's good. TypeScript, unlike flow, makes newer features available with the type data.
On second thought, that might not be such a bad idea. Babel already parses some type annotations, why not also add the little extra syntax supported by TypeScript?
const f = function(a) { return a * 3; } f("stuff");
this will produce a runtime error with TS, Flow will fail to compile it.
People here think that choosing a statically typed language necessarily means you need to type annotate everything, and thats not true. In Haskell and Elm you don't have to explicitly write any types if you don't want to.
Elm doesn't produce javascript that contains runtime errors, and Flow is pursuing a similar goal.
Right but the instant you annotate a, it knows and gives you a good error.
The reason TypeScript did this, to hear them tell it at Build, was because (unlike Flow, although they did not say it) they're a transpiler with a mission to actually make the tool usable with real world javascript.
That's why, for example, type errors don't block code emitting but syntax errors do. It's in service of making a usable toolchain. Flow can be more aggressive because it's not making these decisions (its part of a larger configurable toolchain).
Neither Flow nor Typescript can actually project soundness onto Javascript. Mentioning that is a giant red herring. So long as compatibility with base ecmascript is offered there is code which cannot be verified as sound or unsound without the execution context at hand.
Typescript takes the approach that types are actually a useful tool for expressing concepts succinctly and safely and offers that first. Flow takes the approach that aggressive type inference is a phenomenal way to detect (potential) errors in javascript code, and takes that approach. Neither is wrong.
unless you annotate it with :any
> Neither Flow nor Typescript can actually project soundness onto Javascript. Mentioning that is a giant red herring. So long as compatibility with base ecmascript is offered there is code which cannot be verified as sound or unsound without the execution context at hand.
I don't see how you can say that. Flow can absolutely create a 'sound' type system on top of javascript. Elm transpiles to javascript and has a sound type system that doesn't produce runtime errors. Flow has different syntax but it restricts the type system in a similar way.
I was a Smalltalker professionally for almost 15 years. Let me say this about that: You don't absolutely need type annotations. That said, the information clearly has value in large projects, especially when they've been modified in production for a decade or longer. There were a couple of times when we really wished we could do certain refactorings, but we were blocked because we couldn't be 100% sure of what would end up in certain instance slots.
Keeping your types straight by clear thinking and convention in Smalltalk is about the same cognitive load as wrangling the type system of C++ and avoiding the gotchas there. The difference is that the consequences in the former case are exceptions that show up in production, while in the case of C++, these become coding/dev-testing/debugging gotchas. In exchange for that, you could move considerably faster while breaking things in Smalltalk.
There are also ways to have your cake and eat it too, in 2016, with regards to both type annotation and dynamic environments.
I've always viewed it with rose color glasses. It looks like a wonderful environment to work in, but I'm sure I'm missing something. It seems like Smalltalk was lightyears ahead with it's tooling.
What do you work in now, do you find lack of tooling to be challenging?
I could whip up a custom SQL-query-like query of my loaded code, then have that pop up in a browser. Then I could compose that with another search or another custom query, then maybe even write a syntax-driven automated rewrite of the resulting browser contents.
I currently work in C++ using Visual Studio. It's not that I lack certain tools. It's that those tools are themselves lacking. They are slower, less useful, less nimble, and less dependable than what I'm used to. Mostly, they are slower. When refactoring, it's like I'm using a Dremel, a hand-saw, and cheap bench grinder, where I really should have a full shop with a full set of tools, CNC machine, a lathe, and a 3D printer. Refactoring is literally 10X slower, due in large part to the higher cost of entry to hacking on programming tools.
I understand that people find Babel's plugin ecosystem confusing and intimidating (it is), but I don't think a separate monolithic typescript that reimplements popular babel functionality is the answer.
Right now, we have the typescript ecosystem, the babel ecosystem, and the other wannabe ecosystems. If I like Typescript's type system but want to use babel for async-await (for instance, I'm aware it's in TS next), I'm basically SOL. Babel has more end-users (AFAIK), generally has the first/only implementation of <feature>, and my impression is that the surrounding development community is larger and more active (typescript stuff tends to come down from On High).
For instance, you can use https://github.com/gcanti/babel-plugin-tcomb to get run-time type checking with babel/flow for free. That's really cool! Unfortunately, the same is not possible with typescript (AFAIK), because MS decided that was out of scope. If Typescript was offered as a babel plugin, somebody else could implement it for typescript and we could all be happy.
I've been using both on separate projects (with MS IDEs) and haven't noticed anything major.
TypeScript's type system is very bleh, but its IDE integration IS pretty good across many editors (not just VSCode)
Great news, but I suspect it's going to be pretty difficult to migrate large codebases to account for this properly, even with the help of `--strictNullChecks`. Sounds like days worth of tedious work analyzing every function.
Is it even possible to use these flags with production code?
We don't have good data on this but my perception from talking to people on GitHub is that the vast majority of people using TypeScript run with 'no implicit any' on once they get their codebases converted.
(I'm on the TypeScript team)
Had some problems with React/JSX back in the days.
I believe it's actually a perf gain to run with this set (but I'm not certain).
* npm replaces typings/tsd
* non-nullable types (has to be switched on)
* better control flow analysis (à la Facebook Flow)
* read-only properties
Turning on --strictNullChecks flagged about 600+ compiler errors in our 10Kloc codebase. I've addressed about half of those so far, and I can't say that any of them have actually been a real bug that I'm glad got caught. On the contrary, because of the weird hoops it makes you jump through (e.g., encodeAsUriComponent(url || '')), I'd say that our codebase feels even less clean.
The real value of more strict type checking is when writing new code -- you won't need to spend as much time discovering bugs in development or writing tests for issues the compiler is catching.
$ npm view typescript 'dist-tags'
{ latest: '2.0.3',
next: '2.1.0-dev.20160922',
beta: '2.0.0',
rc: '2.0.2' }
Yet https://www.npmjs.com/package/typescript says>typescript published 5 months ago >1.8.10 is the latest of 447 releases
class Person {
readonly name: string;
couldn't they have just reused `const`?Small correction: The readonly modifier means you can initialize the variable, but can't mutate it (even within the same class). For example, you can initialize a readonly field inside a constructor, something you can't do with const.
Some good docs on it here: https://basarat.gitbooks.io/typescript/content/docs/types/re...
> Read-only properties may have initializers and may be assigned to in constructors within the same class declaration, but otherwise assignments to read-only properties are disallowed.
Thanks for pointing that out.
Say I have a function of arity 4, and want to bind / partially apply (some might say "inject") 2 arguments to it to create a function of arity 2, can TS infer the types of the remaining arguments, or, that the result is a function at all???
I use partial function application MUCH more than classes in the JS code that I write. There just seems to be less to need all that "taxonomy" related refactoring.
"Stop Writing Classes", "Executioner" in "The Kingdom of Nouns" (not!), and all that sort of thing :-)
You put the configuration / dependency parameter(s) first, and the more "volatile" parameter(s) last. Rather than having a constructor call, you partially apply the things you want pre-bound (config, deps) to create a new shorter function that acts as the "do it!" method.
E.g. - write a function to send emails. Put the "reply to" parameters first. Partially apply that data. Use the resulting function to send emails to specific people. Bind on the distribution list name argument. Use that function to send alerts to those recipients. Bind on the content of an alert. Use that to send an alert when needed, without having to come up with any of the input, just the 0-argument function. Overloading, alternate constructors, subclasses??? Screw that. As long as the parameter order is reasonable (least to most volatile), there is seldom anything to be "refactored"
"Currying" just means that you apply a single argument at a time, until you get down to an "arity 1" function, after which the final argument runs the original function with the last remaining argument, rather than returning an "arity 0" function. Here is an example library that does A LOT of currying: http://ramdajs.com/docs/
If I apply/bind a function to my higher order function, is that dependency injection, or subclassing? Who cares.
I like arity 0 functions. They make nice event handlers.
I have been gradually converting to Javascript for the last 8 years. My paradigm has definitely shifted. I know how miserable static OOP is, and won't be going to my grave not knowing :-) (here's the quote: https://www.facebook.com/groups/nodejsis/permalink/142940052...)
For TS to do this, the compiler would need to supply the "apply"/"bind" feature and track that a function goes in, and the list of argument types, so it can check what is applied and track the types of any remaining arguments. Doable, but if it's not built into the compiler, I have to start running a transpile process that buys very little for much of my code.
Say I want to sort a list of objects/records that have a "name" field by name. I can compose some functions to do this, and use the resulting function where needed (regardless of the input object list "type(s)", as long as it/they quacks back with a "name" property/field).
I'm going to assign some functions to intermediate symbols, but that's not strictly required, since functions are an expression/value like many other things.
var name_comp = function( l, r ) { return l < r }
var sort_by_name = R.sort( name_comp )
// alternatively: ... = R.sort( function ( l, r) { return l < r } )
...
var old_list = [
{ name: 'Middle', foo: 'bar' },
{ name: 'Zero', bluk: 'phooey' },
{ name: 'Alpha', answer: 42 }
]
...
var new_list = sort_by_name( old_list ) // ... Alpha ... Middle ... Zero ...
In general, the curried arguments can be primitives and objects, as well as functions.The Ramda library is primarily geared around taking common "collections" types of operations and chaining them together. It has other FP "mathy" stuff that I still have not got my head around yet, as well.
This will be type safe and return a function<T1>(T1 x).
(Disclaimer to typos and erros for typing on my phone)
FWIW, you want to have an operation to bind the first (or first N) formal parameter to a value, and you want to be able to have an arbitrary number of remaining parameters.
Whatever facility would be in place needs to allow for N remaining formal parameters, of various types, not merely do the ("generic" / templated / type-parameter) recipe for one additional parameter.
I am not a Haskell or F# programmer, but maybe the TS team wants to look at what those languages do.
Are these references to blog posts?
https://www.youtube.com/watch?v=o9pEzgHorH0
http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom...
https://www.youtube.com/watch?v=rhV6hlL_wMc (in particular, the quote just after 17:00)
http://blog.johnnyreilly.com/2016/09/typescript-20-es2016-an...
i played with it for a bit before deciding that for my personal stuff i prefer more strongly ML-based languages, but if i ever have to develop and maintain a large team project i'll definitely give ceylon a very serious look.
You can get good at writing the declarations yourself, but it's hugely annoying.