Documenting https://umbrellajs.com/documentation#addclass. The way I documented it is by opening with a code snippet with many of the possible options (which can also be combined!):
.addClass('name1')
.addClass('name1 name2 nameN')
.addClass('name1,name2,nameN')
.addClass('name1', 'name2', 'nameN')
.addClass(['name1', 'name2', 'nameN'])
.addClass(['name1', 'name2'], ['name3'], ['nameN'])
.addClass(function(node, i){ return 'name1'; })
.addClass(function(){ return 'name1'; }, function(){ return 'name2'; })
This is pretty easy to do in plain JS, and of course if you are writing code and using it you just read the first 1-4 lines and know what to do for 99% of the cases, while also noticing there's few "advanced/flexible" ways of using it. How would you even do that in TS?Then there's a classic initializer in JS that works like this:
function myLibrary(arg) {
if (!(this instanceof myLibrary)) {
return new myLibrary(arg);
}
...
}
This is very useful to create a library like jquery that you can initialize straight away without needing (but also being able to use) the `new` keyword, just calling it like a function and always ensures it returns an instance. To this day I haven't found a way of doing this in TS.In this example, I'm not sure why it's the functions responsibility to support all of these options when the user is perfectly capable of manipulating strings and arrays.
Different languages have a grain like wood does. And that subtly directs you by making some things ergonomic and some things difficult to express. I love typescript, but I definitely find it changes the resulting code.
Typescript makes "jQuery style" javascript much more awkward to write, because its harder to type. This is good and bad. I write less scrappy code in typescript - which I think makes it a worse language for quick prototyping. But the tradeoff is that I think its a better language for larger teams / longer lasting projects where functions are read a lot more than they're written.
The actual typescript answer for your API is "don't make your API look like that". Its not always the answer you're looking for.
declare function addClass(...classes: (string | string[] | (() => string))[]): void;
It's pretty straightforward in Typescript. And when you go to implement it, tsc will make sure you cover all the types your function claims to support.> This is very useful to create a library like jquery that you can initialize straight away without needing (but also being able to use) the `new` keyword, just calling it like a function and always ensures it returns an instance.
Avoiding having to type "new" is not a very compelling reason to avoid Typescript, especially because Typescript won't let you make the mistake of calling the function without it. It's just not a problem.
Whether the effort is worth it is, however, a totally different question to whether it's possible.
Just make a static method that does initialization if needed and returns a new instance?
https://www.typescripttutorial.net/typescript-tutorial/types...
I'm trying to not be too hard on people as I read this thread, but it's baffling to me that web devs are getting filtered by features that have been in other languages since the 80's and 90's.
* Only accept an array of strings. Not a single string, not several strings, not several arrays of strings, and certainly not a space/comma-separated list of classes.
* Add another single overload where you accept a function that takes two parameters. That function can ignore its parameters if it wants to, and it returns a list of strings, so you don't need to accept several.
You have the same functionality, it's not harder to use for an end-user, and it's infinitely simpler to type.
For the other 99% of programming languages, that kind of interface makes the addClass implementation too complicated and forces unneeded branching into it. Consider: when the app developer is calling addClass, they _know_ which interface variation they're using. So they can easy write e.g. addClasses instead of addClass ... completely removing the branching from the code altogether.
Your input and output types are much simpler and static analysis is much easier as well.
You use an ambient declaration to declare the missing classish part of the type.
declare function myLibrary(arg: Type): myLibrary;
declare class myLibrary {
member: Type;
constructor(arg: Type);
}
You see this pattern pretty often in DefinitelyTyped.I disagree with this. When working with rxjs I wanted to emit a single string in an error handler. Since strings are iterable I ended up with the characters being emitted.
The library authors added this "flexibility" (implicit conversion from values to observables) which caused a subtle bug that took me a while to figure out. A type error (expected observable, got string) would have prevented this.
> .addClass(function(node, i) {return 'name1'})
^ what is node? What is i? Seems intuitive to think it must be a dom reference and an index. But in different domains it's not always gonna be so clear. Like I am not familiar with umbrella js, but maybe node could be a jquery object and not a plain dom ref? With typescript you can just say
type GetClassName = (node: HTMLElement, i: index) => string | string[]
// see how I added string[]. So I don't have to add yet another example
// of a function returning a string array instead of a string
and then add it to the union of types that can be passed into addClass. Great, no more guessing based on the domain knowledge I have (or don't), it's crystal clear. And it forces the lib developer to have the discipline to make it crystal clear, which they usually don't I'm afraid.
grid.selectRows(2) // index grid.selectRows([3,5]) // range grid.selectRows([[1,2],[4,6]]) // multiple ranges
It fits in the JavaScript spirit of "we will make it work" which I love.
Other major thing that made me decide to develop in es6 instead of typescript was compilation times. After a ctrl+s it had to compile ts to js for 10 seconds, which is annoying for me, as i like to check & test every minor code change.
Do you also use == and != for comparisons by default?
Typescript has a --watch mode that compiles as you work. Most test runners also often have a --watch mode. Test runners that support Typescript directly don't even need Typescript's --watch to be running as they'll do both, compile and test in a single step as you save. Anecdotally, the time it takes to run tests dwarfs any Typescript compile times and in a --watch mode of a test runner there's almost zero difference in the time it takes to watch ES2015+ tests or Typescript tests.