Note from 2023:
TS+ is an experimental fork of TS, don't use it in prod.
Hi!
So, what's this post gonna be about?
Well, with the Effect com...
For further actions, you may consider blocking this person and/or reporting abuse
First Effect, now TS+. There was no better day to be a functional programmer than today :)
After spending a lot of time with pipe, no useful language supported pipe in sight, and lots of imports, hard to discover modules and apis, ts+ is such a breath of fresh air, hitting all the right notes at the right time!
Already adopted fluent, static and call extensions, and globals. Can’t wait to go further with operators, lazy args, rules and beyond.
And soon, the stdlib with next gen Effect!
Lodash/Underscore are not Fluent APIs they are just modules of functions that is ok, there is a usability compromise though take for example an array "a" to map "a" you do "a.map(f)" doing "map(a, f)" isn't as nice, nor doing "pipe(a, map(f))", jQuery has a fluent api but that sort of comes from a different era and nobody is tree shaking jq. Fluent APIs cannot be tree-shaken (at all), class methods cannot be removed nor renamed, libraries like fp-ts or rx-js have moved away from those API because they aren't shakable and they aren't extensible (i.e. adding a method to a class coming from a library)
This is a fork of the compiler it is not adding any further compilation step, and it is fully compatible with normal TypeScript (it really doesn't want to be against TS at all :))
I guess you could say it's a ttypescript or ts-patch with already great built-in patches.
Maybe I didn't get something bug I feel like the base issues could have been solved in an extremely easier fashion by not using class-based OOP
No, just use functions
No, just use functions
No, just put the functions in different files
No, some people just use functions
"No, just use functions" => this is in the context of wanting a fluent api, if you want a fluent API plain functions are of no help.
"No, just put the functions in different files" => by the way this is 100% irrelevant for tree shaking, you can put all the functions in the same file and the result is the same (actually even better in size terms because you have less modules).
"No, some people just use functions" => yes people like me use just functions, but they also know what a function actually is.
both RxJS and fp-ts uses pipeable functions. pipeable functions are as you say "just functions", the same way extension methods are "just functions"
“reactive” libraries like rxjs are event systems. Because they have a disconnect between the data being sent, and overhead for subscribing/unsubscribing, I wouldn’t consider them anything related to fluent design patterns.
I personally prefer pure functions, and changing state at the very last pop of the call stack (firsr method that calls pure functions is responsible for setting state, no where else can set state). Similar to fluent, but without the overhead of returning a new object. And easier to debug what is going on (fluent can turn into a finite state machine).
Fluent here refers to a style of API not the design pattern and has nothing to do with mutating state, the IO example above is 100% pure and functional in every possible interpretation.
Use Nim programming language and you don't care whether it's a method or function
You write whatever Style you want
Big part of the project is to create something both really nice and with great interop with the wider ts ecosystem it's not only about style :)
That I really don't understand. I'm not familiar with IO or Effect but for example in lodash when I wanna use
cloneDeep
I'll just doimport cloneDeep from 'lodash/cloneDeep';
, yeah I have to know which module to import but it's not giving me a headache. Also there's no constructors and no additional methods, and the use is evident. So I don't see any case where a similar lib would cause these issuesSure you can use directly lodash and direct imports, the problem becomes more apparent when using libraries that cover a bit more surface compared to lodash (like Effect, like fp-ts, etc) and in many codebases that translates to a large set of namespace imports
import * as F
, when usingF
you have everything inside and discoverability is problematic. For example only the Effect module in effect-ts provides 1000+ functions inside (they are all as you say "just functions") but you have to know what the "just functions" do, i.e. is the function constructing an effect or is a function combining? i.e.map
combines,succeed
createsWhat can you do of the above with vanilla JS? Derive runtime codecs? have tree-shakable fluent APIs?
Was really confused on looking through
Effect
and its community libraries and seeing fluent API. I was like "what's going on here", and I kept seeingtsplus
in the code and tsconfig. I was about checking npm for tsplus then found your post on the discord channel.Yeah, incorporating those functions (map/flatten/etc) you end up with all, for effect that can be huge there are modules with 1000+ functions
@jfbrennan importing individually gains tree shaking but would mean losing chaining/fluent and therefore discoverability and usage context.
or piped
With ts+ you keep chaining/fluent, discoverability and usage context, while it gets compiled down to individual imports for tree shakability and optimisations. win-win.
The bigger the library (or the more libraries), with the more type classes/modules, the more the win is.
Are the functions showed here part of the compiler itself ? So I can just use them without any extra installation?
It looks awesome, good work, and kudos for going one step further of what most libraries could do and fork the compiler.
The functions/values as in their material implementation is in library code, in this case what's shown is part of
@tsplus/stdlib
that you can use with or without the compiler fork and should be installed with classic npm/yarn, when using the compiler fork the same functions defined in stdlib (or any other packages like@effect/core
, or your local code) are used as concrete implementations but additional syntax is generated and made available to use, the additional syntax includes fluent methods, operators, etc. Also when using the compiler fork your functions can specify derivation rules and values can be defined as implicit instances that are used when a call toDerive()
is compiled in order to generate things like Encoder/Decoder/Guard/Equals and any custom typeclass that you may want.Looks promising! But why the use of comments? It is not really friendly to use. Why did you end up with this solution over new keywords or typescript decorators for instance?
because changing syntax would break compatibility with tools like eslint or prettier, additionally you are supposed to be able to integrate TS+ progressively in code potentially even directly for projects that have types maintained separately (so you need something that you can write in d.ts which is add only and doesn't break any standard TS/JS). TypeScript itself is progressively thinking more and more of types as comments and their recent TC39 proposal goes in that direction too. I can see how it may be perceived as non friendly to use but in practice our feeling after having built huge codebases like github.com/effect-TS/core/ with it is that it is indeed very friendly to use and those comments only end up representing a small portion of your code.
I was also not amused by that at first either, but because it's basically just enhancing wiring metadata (actual types are still expressed as usual), it's actually pretty good!
Hey, I’m wondering what The current status of that project is as there’s been no commit on the docs or stdlib over the last year. Are you guys still using it on effect for example?