40 ms·
TypeScript is terrible for library developers
- dangarbri3 4y agoI think valid points are bad about typescript being bad, like without a real debugger it's going to be hard to debug anything. But I firmly disagree with how the article begins. > In effect, we are shifting complexity from end-developers to library developers. That is the whole point in creating a library. To hide complexity in a nice easy to use interface/API.
- Smaug123 4y agoYeah, the author appears to be complaining that Typescript is forcing them to stay honest even while they perform Mad Shenanigans like dynamically constructing types :/ if TS didn't check it, it would be down to your users to report the bugs in production!
- franciscop 4y agoI don't think it's very fair. As a library developer myself, you try to make you user lives easier, which implies being flexible in what you accept when possible. A couple of examples I struggled with recently: Documenting https://umbrellajs.com/documentation#addclass 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.
- Smaug123 4y agoThere's "be flexible in what you accept", and then there's… "take a comma-separated string which you could parse into your arguments" :)
- vbezhenar 4y agoMay be I want to pass JS string to be eval-ed. Flexible, huh.
- HideousKojima 4y ago>To this day I haven't found a way of doing this in TS. Just make a static method that does initialization if needed and returns a new instance? https://www.typescripttutorial.net/typescript-tutorial/typescript-static-methods-and-properties/ 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.
- phailhaus 4y agodeclare 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.
- franciscop 4y agoThat's an order of magnitude less clear in what the function expects than the examples I gave IMHO
- deleted 4y ago
- qudat 4y agoThanks for reading the article! > That is the whole point in creating a library. To hide complexity in a nice easy to use interface/API. I think that's a fair point, but generating types that satisfy all use cases is very challenging to get right -- disproportionately so. I could see a world where -- without proper tooling and growing complexity -- typescript libraries becomes so difficult to maintain that people give up or burn out. Maybe that's a pessimistic outlook but I already feel that way some days.
- Chabsff 4y agoIn strongly-typed programming languages, which includes Typescript, figuring out the types *of the interface* is not something that's done after the fact. `@types/*` is an exceptional project meant to back-port JS libraries to TypeScript, but that's the exception, not the rule. If you write a library in TypeScript, determining what types are present as part of the interface is one of the very first thing that should be done.
- mrkeen 4y ago> In strongly-typed programming languages, which includes Typescript, figuring out the types is not something that's done after the fact. Too broad a statement. There's loads of value in having a compiler figure out types for you after/when you write the code.
- Chabsff 4y agoHard disagree as far as the portions of it that are part of the user-facing public interface are concerned. But granted, as a general rule you are correct. I was referring specifically to API interfaces.
- overgard 4y agoIf you're talking about type-inference, sure, I guess it's fine. If you're talking about figuring out what types you're going to accept, you should absolutely be defining that on your own up-front. If you don't even know what your types are how is an end user going to figure it out?
- heisenbit 4y agoOften libraries are bootstrapped from application code. Having a step function in complexity is not helpful in fostering an ecosystem with a broad range of maturity.
- johnfn 4y ago> That is the whole point in creating a library. To hide complexity in a nice easy to use interface/API. Totally agree. Minor ergonomic changes in a library have a wildly disproportionate impact on developers. If I save a developer 5 seconds with a better type, and I have 1000 developers using my library, that's 5,000 seconds I just saved - and that's assuming they only ever use my type a single time! With this in mind, I'm totally OK paying a tax on making libraries a bit harder to write, if it means that the benefits of stronger types fan out. After all, writing that type could take 4,995 seconds for me to write and still be a net positive. And honestly, 5 seconds isn't even close to accurate. Good type definitions have saved me hours.
- henning 4y ago> In effect, we are shifting complexity from end-developers to library developers That is the whole reason to use libraries. This blog post shows that types make development more enjoyable by shifting the complexity burden to library authors, who are vastly fewer in number than library users. It is a clear win.
- shadowofneptune 4y agoI would have liked to see examples. My own instinct here would be to use simpler types, but examples could show why that isn't desirable.
- qudat 4y agoAgreed. I updated the blog to add an example. Copy/pasting here: I spend a decent amount of time in the redux world so `redux-toolkit` is a great library to see how types are done *correctly* in a real codebase. To be clear, they do a fantastic job with types, but the level of complexity is pretty startling. https://github.com/reduxjs/redux-toolkit/blob/master/packages/toolkit/src/createAction.ts#L58 https://github.com/reduxjs/redux-toolkit/blob/master/package... That is just one example but the codebase is riddled with complex types. Also, when you look around, note the amount of types vs actual code. It's pretty common in style guides to never nest ternaries. In typescript, that's the only way to narrow types based on other types. It's a mess!
- shadowofneptune 4y agoThank you.
- nkingsy 4y agoAlong the lines of "just use a dynamic language", we use unknown and any type for a lot of our internal stuff like this. Strongly typed shell, whatever works core.
- meheleventyone 4y agoI suspect it’s a case of bolting on types to soupy JS but would also love to see some examples. I agree with the other commentators that part of the point of a library is to suck in complexity but if you’re regularly doing high level type kungfu there are probably bigger structural issues.
- ryanmcbride 4y agoThey probably just keep running into issues that seem really trivial but are unable to find info on fixing. It's the reason I put off writing things in typescript until relatively recently. In that vein, if anyone here can tell me how the hell you functionally map over a typed object by key in typescript I'll be eternally grateful. I always wanna do something like Object.keys(typedObjName).map(...) but that doesn't work. It's so stupid and small and minor and it's never really prevented me from getting something done but it drives me out of my mind that I still can't find any clear documentation on how to do it.
- zethraeus 4y agoIf you write your library in typescript, not JS, do you still have any of these problems? If not, it sounds like one core issue is 'adding types to an existing untyped codebase is hard'. This checks out. :)
- no_way 4y agoWriting new library and expecting people to actually use it without providing types is not realistic. You can write library in JS, but you will still need to provide types, since that's what ecosystem is right now.
- wizofaus 4y agoI disagree it's hard per se, but I'd agree it's hard to do well. Especially if you have a bunch of JS functions that return (or expect) objects with very similar but slightly different properties. Figuring out the overlap and the semantic relationship between the types is often challenging, because the original authors never thought about the problem in terms of what types of objects they were dealing with.
- benjismith 4y agoI liked the article, and I'm sympathetic to the overall point... > The kind of hoops I have to jump through to get types "just right" in a web app versus a library is dramatically different. It's rare in a web app for me to need constructs like conditional types, type operators, and overloads. As a library developer, they are heavily used. These constructs are highly dynamic and embed logic into your types. This leads into my next frustration with typescript which is debugging. I would have like to see some examples of "conditional types, type operators, and overloads" in action, and an argument for why these constructs are so much more prevalent in library code than in application code. I don't have a counter-argument, and I don't have any reason to doubt the author's insight, but after reading the article I don't feel like I have an increased understanding of the problem-space.
- usrusr 4y agoIt's been ages since my last dive into the js galaxy, but from my outside perspective I read that as "the usual mess that we like to do to provide awesome backwards compatibility when introducing wildly changed API generations is very difficult to sneak past the typechecker". Not sure that I read it correctly, but it would certainly fit "conditional types, type operators, and overloads". Why are they more prevalent in library code: to make changes non-breaking (or breaking, but fixable with minor tweaks). Of course types can also be a solution to this problem, by promoting consequences of incompatible change from runtime to compile time, but that only holds if you can assume that all calling code is type checked.
- mirekrusin 4y agoBecause in application you're on consumer side, you have concrete types you're working with, in library on the other hand you're often providing generic code with parametric polymorphism, some constraints, you'll use type mapping etc. Before judging it as "terrible" it would be good if author has more constructive criticism - if typescript is "terrible" what is not "terrible", haskell? What are specific things that can be changed to make it simpler? What if typescript is actually very good but the underlying type theory is just inherently complex? You also have to appreciate what kind of value it brings to library users - and imho, in many cases, the value is so high that the whole discussion is a nobrainer. In my opinion - if you want to use typescript, you need to learn it, especially when writing libraries. It doesn't make sense to want to use something and not want to learn it at the same time.
- mckravchyk 4y agoI agree that there's much more type wrangling when developing a library vs. typing regular app code. I don't mind it all though.
- mpolichette 4y agoI can empathize with the author here that types can be very challenging to get right, especially with high amounts of dynamism. However, I think that saying it is "terrible for library developers" is a bit far. I think its terrible for developers who want to make use of advance types... which ultimately doesn't depend if you're a library dev at all. It boils down to: "Typescript learning curve gets really steep after the basics" The author mentions they help maintain redux-saga. I don't want to dig on them, but from my personal experience, that library takes you down quite an opinionated application path with complexity inherit to it. Heck, just making types for redux was a pain, let alone adding async and additional composability. My take is that the author has chosen complex tech to work with, and that influences the complexity in their types.
- vosper 4y agoSomething I've long wanted is a type-explainer - something that will let me highlight parts of a type definition and tell me in English what the fragment means. The example that OP linked elsewhere in this thread [0] is a good one - I know what parts of that mean, but I've never seen "T extends string = string" before. [0] https://news.ycombinator.com/item?id=32569708 https://news.ycombinator.com/item?id=32569708
- Smaug123 4y agoIt's just "T extends string", with a default value of `string` if you don't supply T.
- deleted 4y ago[deleted]
- sedro 4y agoAnd the purpose of "T extends string" is to carry the value of a string literal. For example, there's the string value "foo", but there's also a type "foo" which extends string and has only the one possible value.
- throwaway247322 4y agoThat would be cool to see, actually reminds me of the cdecl explain project [1]. [1] https://cdecl.org/ https://cdecl.org/
- eyelidlessness 4y agoThe problem with the premise of the article is that it presupposes that a library’s interfaces will, and ultimately must, be complex. The great thing about TypeScript for library development, if you start with types, is that it strongly encourages you to create simpler and less flexible interfaces. That’s not to say you don’t sometimes need (or won’t sometimes choose) to use some of TypeScript’s more complex features. But a lot of the time you won’t, or should think seriously about whether your interfaces are becoming too complex. Much of the complexity of TypeScript’s type system is a direct result of excessively dynamic interfaces in existing, untyped JavaScript. Starting with types is a good way to catch that early, rethink the interface, and either isolate it or avoid it entirely.
- matsemann 4y agoIt was bad the first few years, with existing code being hard to type because it was creatively written. But now that almost everything is somewhat typed, JS has converged to a way of writing code, and you should consider the tradeoffs before choosing a different path than the current norm.
- fullstackchris 4y agoI really _wish_ this were true, but go look at a vareity of "modern" React projects. React is so flexible that I've seen nightmare implementations of what could be reduced to just a few short lines. Then people turn around and blame React as a 'garbage framework'. Then if you talk about a much more verbose and strict framework like Angular, people turn around and complain "I can't do what I want with this overly opinionated framework!" Damned if you do, damned if you don't. However, if you look behind the curtains of these infamous gripes (some of them so often repeated they are cliché), 99% of the time its people who just haven't spent enough time around a certain framework or language and go create a rant post (similar to OPs post) You're free to love the tools and languages you use all the time. But it's bad practice to go around bad mouthing tools and frameworks you don't full understand or haven't used productively.
- zdragnar 4y agoIt also was missing a lot of crucial features early on, which made typing certain things impossible. Even now there's a few things that are a PITA to type, but as you say those edge cases can be largely avoided.
- latchkey 4y agoThis is a matter of opinion. I wrote a set of React components that gets 46,000 npm downloads a month and typescript is a godsend. My library is a bridge between two heavily popular projects, so my dependency tree is fairly intertwined. The library solves a real user problem and does it efficiently. It isn't totally perfect, but it covers 98% of the use cases. I wrote comprehensive tests as I developed everything. I have good documentation. I have an example app people can play with. I have codesandboxes. Yes, it was a lot of work, but that's what building products is all about. I've maintained this library for over 3 years now. I've upgraded it many times as the underlying dependencies have changed. A few times with backwards incompatible changes. I get outside contributors doing great work. I do releases on a regular basis, without worry, because my test suite is that good and because I know that if the underlying types change, tsc will catch that too. These things have saved me countless hours of work finding bugs and fixing issues. In other words, I call bullshit on this entire blog post. Ignore it. Typescript is the correct solution. What is the alternative? Just using JS and letting things break without knowing it? Come on. Learn how to use types. Learn how to use a professional IDE, like IDEA, that shows you what's wrong as you develop. Learn how to write tests. Learn how to use a debugger. These are all things any decent developer should know and practice on a regular basis.
- somenewaccount1 4y ago[flagged]
- latchkey 4y ago> TypeScript is terrible for library developers That's the title. That's the whole premise of the post. > his primary gripe specifically as a library developer - is that the knowledge base for library developers is very sparse. No, it isn't.
- mattmanser 4y agoIt's the first of his 5 gripes. There's only 5 of them and they're titled. A few of the other gripes also mention the lack of documentation, so it definitely appears to be his main gripe. I agree with GP, you don't seem to have read his article and knee jerked a reply. And all you have to do to prove your point is to link some great documentation explaining how to make complex types for libraries and how to test them. Which you haven't.
- franciscop 4y agoThe only convincing reason to use TS I've seen so far as a library author, which TBF is actually not about TS but about TSDoc/JSDoc, is how the autocomplete in VS Code works. Going from an empty/barebones autocomplete to actually having the documentation in-line is a pretty nice extra feature for my users IMHO: https://twitter.com/FPresencia/status/1545932895126175746 https://twitter.com/FPresencia/status/1545932895126175746
- acemarke 4y agoHeh, it's amusing to see Redux Toolkit referenced here. I'm one of the two main RTK maintainers. My co-maintainer Lenz Weber is responsible for most of our TS type wizardry. Agreed that writing TS types for libs can be a pain. I actually did a talk recently on "Lessons Learned Maintaining TS Libraries" [0], where I talked about some of the techniques we used, and some possible TS changes that would be helpful for us as maintainers. As one recent example, TS made a change in a 4.8 pre-alpha that broke RTK's `createSlice` types. Lenz tried to come up with a fix, couldn't, and had to add a workaround to check what TS version is being used and specifically use an altered type. Since there _isn't_ a good way to know what TS version is being used, Lenz resorted to hacking together a new package that abuses the `typesVersions` property to define a different TS type for _every_ TS major+minor version combo, and then used that to decide what the RTK type should look like conditionally [1]. Another pain point is debugging type transformations. I reworked the Reselect types in 4.1.x to do a much better job of inferring the argument types for the final selector, based on the intersection of all the input selector arguments. This ended up as a monstrous type that does a types-level map + transpose + intersection [2]. It took me weeks to get this working right, and I frequently had to break it down into multiple small intermediate types to see how TS was processing each step. I know that someone on Twitter was recently working on an alternate TS type-checker based on bytecode, and they said they had some kind of a working types-level debugger [3]. Having something like that officially, where I could see each step of how TS was transforming the types, would be _hugely_ valuable. There's a couple folks like AndaristRake who are able to dig into the internals of the TS compiler itself to trace how it's interpreting the types. I definitely don't have that ability :) [0] https://blog.isquaredsoftware.com/2022/05/presentations-ts-lib-maintenance/ https://blog.isquaredsoftware.com/2022/05/presentations-ts-l... [1] https://github.com/reduxjs/redux-toolkit/pull/2547 https://github.com/reduxjs/redux-toolkit/pull/2547 [2] https://github.com/reduxjs/reselect/blob/v4.1.5/src/types.ts#L100-L148 https://github.com/reduxjs/reselect/blob/v4.1.5/src/types.ts... [3] https://twitter.com/MarcJSchmidt/status/1539787500788613120 https://twitter.com/MarcJSchmidt/status/1539787500788613120
- helsontaveras18 4y agoI agree wholeheartedly that debugging types is very difficult. The best we have is hovering our mouse over the definition to see what type was created from the definition. Obviously not great. Also, debugging type differences with deeply nested objects (like what happens with graphql schemas) can be hugely painful. You need to copy the error message to its own file (since the errors can be huge) and debug what specific piece failed. I do feel the Typescript documentation is lacking and the only way to get better is to read open source projects to see how others have done it… which is only helpful when they’ve solved the exact problem you’re looking for. It’d be great to have a recipe book of common advanced typescript manipulations and how to compose them together.
- chadlavi 4y agoAs someone who started our inner-source react component lib with typescript, it's actually really great
- progx 4y agoFor simple interfaces it is. But wait until you got complex dynamic things.
- yashap 4y agoAnother way to phrase this is “statically typed languages suck if you want to write highly dynamically typed code.” That’s true. I think there’s 3 options here: 1. Keep writing code in a very dynamically typed style, despite choosing a statically typed language. Just deal with/stomach the extreme type complexity that is necessary to model your dynamic style statically 2. Keep writing code in a very dynamically typed style, and switch to a dynamically typed language 3. Stop writing code in a very dynamically typed style. If you’re using a statically typed language, write code that embraces static types IMO 2 and 3 are both reasonable choices, but the author is deciding to choose 1, which is of course painful. I strongly disagree that libraries must be super dynamic though - that’s a pure style choice that some library authors adopt, but you can absolutely write basically any library in a static types friendly style, you just need to reflect that in your interfaces. I guess the one thing that IS TS specific is that ppl can write their libs in JS, then try to add types to it, and if they chose crazy dynamic interfaces, it will be an incredible pain to statically type. But honestly, you could just say “this is a JS lib, there will be no TS types.”
- boffinism 4y ago> Another way to phrase this is “statically typed languages suck if you want to write highly dynamically typed code.” Reminds me a lot of the NoSQL wars which eventually boiled down to 'Non-relational databases suck if you want to store highly relational data'. As ever, there are no silver bullets, only the right tools for certain jobs.
- jbirer 4y ago(Hoping to not invalidate anyone's concerns with this comment) The majority of complaints I heard on Typescript were in the lines of: "I should be able to do this X thing that would not fly in a static language / not a good idea". Many times Typescript caught me doing stupid things like passing the wrong type or not checking data adequately, also forcing me to comment my code by describing shape of the data. It was a life saver for debugging, though it's not perfect, it's more like lipstick on a pig for a badly designed language.
- thdxr 4y agoA great counter point to the thinking in this article is this snippet by Dan Abramov: https://overreacted.io/what-are-the-react-team-principles/#absorb-the-complexity https://overreacted.io/what-are-the-react-team-principles/#a... Yes we need better tools as library authors but absorbing this complexity is our job. The more we take advantage of what Typescript can do the fewer types the end users deal with and the better experience they have. Making your library's internals simple should be a non-goal. The number of people dealing with it will be a fraction of the people dealing with codebases using your library.
- Veuxdo 4y ago"testing your types" If you find yourself thinking you need to test your types, you've taken a wrong turn somewhere.
- Hirrolot 4y agoDoes it mean that languages should prohibit type-level programming (or type-valued functions), like in Idris?
- Smaug123 4y agoIn Idris, you've typed your types. Much easier to deal with.
- CRConrad 4y ago>In Idris, you've typed your types. I've always typed not only my types, but functions, programs, tests, everything, in every language I've ever coded in. OK, sometimes I first write stuff (in pseudocode, or at least bad syntax) on paper first, but in the end I always type it into a code editor on the computer. Type type type, clickety click click clack...
- madsbuch 4y agoIt most certainly does not. It means that types are not subject to tests much like you don't test your tests. types / tests are usually written in a denominational way and keeps the operational semantics of the program in check.
- z3t4 4y agoLibraries need good documentation with reference and code examples. What libraries don't need is complex type annotations that wont make it into the compiled code anyway. The worst documentation I've ever seen is the one that use the types as documentation, looking at you the Language server interface.
- andrewallbright 4y agoI think the author is good with naming symptoms and I think they miss the true culprit. It's not typescript that is causing this pain, no it's the pain of getting correct abstractions laid down in code. It's truly the pain of code design activity. Typescript and library programming is just forcing that pain to the surface instead of hiding it away. I know this because I struggle against these "pain during code design" & "get abstractions right" forces when I program. Declaring types is really declaring what domain objects your program cares about and function signatures are really just describing interactions that can happen. So what 'domain objects' should meaningfully exist in my program and how do they interact? A bad abstraction can burn up a lot of time, so make sure you check your abstraction. I typically check mine describing stories to my friends (or rubber duck) and ensuring I'm using plain English and the other person doesn't get lost. YMMV When you're doing web client programming you're typically using a library to accomplish work, and much of that work is reacting to user input and rendering data. I would argue that because so much of the linguistic heavy lifting has been done for web client programming, practicing the abstraction exercise is done less than in other programming domains. Doesn't mean it couldn't, just trying to highlight a difference in programmer domains. This is why the pain is more apparent in library programming than web client programming. I imagine that advanced individuals in code design understand more of the connection between math and programming and are capable of describing systems of interesting work in few simple statements. I hope to reach those heights someday.
- deleted 4y ago[deleted]
- deleted 4y ago[deleted]
- progx 4y ago"to spend less time making tsc happy" signed! I feel i spent more time with that than with the development of the code ;-)
- qbasic_forever 4y agoI wish there were a formal subset of typescript that was go-like in design. Interfaces, structs, and simple types but not all the class-based object oriented complexity. A focus on composition instead of inheritance. I like typescript but really worry that it's fueling a boom in unnecessary complexity and architecture. Are we going to look back at monster typescript codebases in the same way we look at monster java codebases riddled with abstract and redundant layers of complexity because the "design patterns" say to do it?
- mirekrusin 4y agoYou don’t need new language, you can just not use classes ie. [0]. [0] https://github.com/preludejs https://github.com/preludejs
- finder83 4y agoLike many here, I love typescript for library writing, at least internally. I've not made any big npm packages, so not sure how that would do, but I imagine I'd like it a lot too. What I hate is getting the build system set up to generate the right combination of .js/.d.ts files to work with the build system of whatever I'm using it in, particularly for libraries that use any form of preact/tsx files. I must be seriously missing something, but after 5 years as a node/react developer I still suck at making build pipelines for new projects.
- brundolf 4y agoI find that most of the pain/complexity around TypeScript types happens when you're trying to write super dynamic or polymorphic JavaScript-style code and then put types on top. This comes out especially when adding types to an existing codebase. I can definitely see how this would affect library authors more than application authors, but I'm not sure it's TypeScript's fault, and I think it can be avoided by making different choices about what interfaces you expose Or, worst-case, just weakening your types. Plenty of libraries have weaker types than they could have, but sometimes it's justified because it would be hard to get them exactly right
- Hirrolot 4y agoI have a similar essay entitled "Why Static Languages Suffer From Complexity" [1]. I don't deal with TypeScript, so it's up to you whether the essay relates to it or not. Basically, the idea is that languages make type-level and value-level programming different in surface, while they're (or at least can be) the same. From hence we have type-level astronautics that boggles library developers' minds. [1] https://hirrolot.github.io/posts/why-static-languages-suffer-from-complexity.html https://hirrolot.github.io/posts/why-static-languages-suffer...
- ummonk 4y ago> There are a lot of reasons why typescript sucks for library developers, but at the end of the day it reduces developer productivity. In effect, we are shifting complexity from end-developers to library developers. Isn't that the whole point of libraries? Instead of having a hundred end-users trying to understand a library's untyped API, we save overall developer time by having just the one library developer type its API.
- overgard 4y agoYou only really need super complicated types to represent existing very-dynamic javascript libraries. If you're starting from scratch typescript is as easy and/or easier than javascript. If you do have incredibly complicated types, it might be a sign that you have a bad design. At work most of the typescript libraries I wrote just ended up using interfaces and enumerated strings and occasionally a union type. Sometimes I'd use "never" to prevent certain things, but I can't say the types ever had to get much more complex than that.
- rikroots 4y agoMy personal experience as a library developer, who has written my library in JS, not TS ... TS is an excellent choice for a lib dev starting a new project today. I can see the advantages of using TS for the library code - in particular for a library that gets popular and welcomes contributions from other developers. However TS is a nightmare for someone like me who: 1. started writing the library 9 years ago; 2. has let the library get "quite" big; and 3. has only learned to use TS in the past year (for the day job) and is nowhere near to becoming a types expert. I've had experience of people suggesting I rewrite the library in TS. Sometimes those suggestions have been quite 'evangelical' in their tone. As an (essentially) solo developer I just don't have the time, capacity or willingness to do that work - however much the end results might please others. I also understand that having type definitions file for the library's interface is, nowadays, a critical factor if the lib dev wants others to use the library in their projects. But writing a .d.ts file for a large, mature repo to at least help those potential users can quickly turn into a World of Hurt. I know this because I've done that work[1] and I never want to do it again. As much as I know that TS is a Force for Good in the JS coding world, there are days when I detest it! [1] - link to the Scrawl-canvas .d.ts file on GitHub - https://github.com/KaliedaRik/Scrawl-canvas/blob/master/source/scrawl.d.ts https://github.com/KaliedaRik/Scrawl-canvas/blob/master/sour...
- oefrha 4y agoProps to you for doing a painstaking job. After-the-fact .d.ts for large mature libraries usually end up with too many anys, or subtle breakages that necessitate @ts-ignore, or a combination of both.
- kupopuffs 4y agoInteresting. you write your .d.ts file by hand?
- rikroots 4y agoYes. I wrote the entire .d.ts file by hand. I did look at including JSDoc comments in the .js files to define types and function signatures, from which I could then autogenerate TS documentation files. But the results were a mess, and they ruined the existing documentation. Given that documenting the code in a way that allows me to autogenerate doc files (in a format that I like) is paramount, I abandoned that idea. Also, the library's structure just doesn't sit well with my limited understanding of TS and TS definitions. I got the impression from the TS docs that the TS developers really like JS classes, and are not that keen on ES6 modules - which is unfortunate because my library makes heavy use of prototypes, modified by mixin functions. So I hand-wrote a single definitions file in a way that matched as closely as possible the library's structure and preferences. Hopefully that file is enough to give developers some useful tips in their preferred IDE when they use the library in their projects. But I've only tested this in Sublime Text.
- nwsm 4y agoThe article boils down to asking for the TS team for better documentation and tooling. Hard to argue with that I guess. > In effect, we are shifting complexity from end-developers to library developers. Is this not why libraries are written in the first place?
- paulddraper 4y ago> Why are there no guides on the typescript site about library developers? What about a guide on the recommended tools for a library developer? One interesting thing about Typescript is that it prefers .ts to .d.ts files. So if you ship you .js, .js.map, .ts, and .d.ts files next to each other, your downstream consumers will be running expensive type inference on the .ts. Instead, you have to manipulate package.json entries so that the .ts and the .d.ts are separate. (Or inline sources into source maps and exclude .ts from the package.)
- throwaway247322 4y ago> testing types Right, this happens in any language where you are writing type lambdas or functions at type level, which makes sense actually. We've been doing this in C++ as well for years... On another note, Redux is fundamentally a bad experience in typescript because the action type must extend from `AnyAction`, so it poisons the well. What we need is a first-class typescript state container with a rigid API, even better would be first-class enums and pattern matching... Writing generators isn't fun in typescript, so yes I imagine redux-saga would be painful.
- acemarke 4y agoNote that our official Redux Toolkit package, linked in the article, has complex TS types specifically _because_ we work to simplify the TS usage experience for our users. Here's all you need to do as a typical Redux app developer to get started using Redux Toolkit with TypeScript: - https://redux.js.org/tutorials/typescript-quick-start https://redux.js.org/tutorials/typescript-quick-start Note that we specifically tell you to use a `PayloadAction<MyPayloadHere>` type, which results in well-typed reducers and automatically generates strongly-typed action creators to match. If you're using Redux at all, you _should_ be using Redux Toolkit to write your Redux logic.
- mcluck 4y agoI could not disagree more. I absolutely love using TypeScript for the libraries that I write and maintain. > There's great documentation and blogs for end-developers but there's very little for library-developers Because there isn't a difference. I write my applications the same way that I write libraries. TypeScript gives you the flexibility to do that as well. If you want to use looser types in your apps and in your libraries, go right ahead. Some people may want more accurate types coming from your library. They'll either improve them or pick something else. You aren't required to appease them. I know that you stated that you reject this notion but just now I was working on a relatively straightforward React app and I've got a number of places where I'm doing slightly more advanced types. If you aren't, you're probably leaning on library developers to do that for you which is fine but that's a choice. > How do library developers debug their highly dynamic and heavy use of conditional types, overloads? I literally just make a number of assignments and hover over the types to verify that they look right. There are better ways of testing these that I'll get to later. // Hovering over this will either show what I want or not type ComplexFoo = ToComplexType<Foo> Sometimes those types might look nasty and be difficult to parse so there are ways to force TS to simplify them for inspection. There are even libraries[1] that help with that. > I spend a decent amount of time in the redux world so redux-toolkit is a great library to see how types are done Redux is an inherently very dynamic system. It's dynamic by design. Capturing all of that dynamism in a strict system is _hard._ `redux-toolkit` and related codebases are not representative of the normal struggles for library developers. Additionally, see point 1 about how you can choose how good your types are. It would be technically correct for `createAction` to just return interface Action { type: string payload: unknown } They choose to make their types better so that developers don't have to carry that burden. > It's pretty common in style guides to never nest ternaries. In typescript, that's the only way to narrow types based on other types I'm always open to syntactic improvements. If someone finds a way to make the type syntax simpler without conflicting with existing JS syntax then I will be very happy. That being said, the syntax isn't so inscrutable as to be unusable. It just takes some getting used to. > It's not enough to test your types against the latest version of the typescript compiler either, you also need to test against previous versions I disagree. The TypeScript team does a very good job of keeping things backwards compatible. In the rare case that they don't, your library is welcome to state that they only support certain versions of TypeScript. This is a pretty standard problem with any sort of dependency. Nothing about TypeScript makes this particularly difficult. If you are going the extra mile to check multiple versions of TypeScript then you're awesome. > This new class of tests are in their infancy and there's a baron wasteland of tools that are now deprecated or partially maintained My opinion: a lot of these tools become unmaintained because they aren't necessary. Testing types is pretty easy. Include these two functions and you're golden. function generateType<TReturn>(): TReturn { return null as unknown as TReturn } function assertType<TExpected>(value: TExpected) {} Then testing your types is as simple as assertType<Expected>(generateType<ComplexThing<number>>) > When first attempting to contribute to a project, one must grok the application logic as well as the type logic. If you're running in to this then those people are doing it wrong. Types should make impossible states impossible and do their best to make the application logic the only thing that is possible. If you understand the application logic, you understand the type logic. They're one and the same. > I shouldn't have to read the typescript compiler source code in order to figure out why it's resolving a piece of my code to a specific type. You shouldn't and you don't. Better documentation is always better though and I agree that more in-depth first-party documentation would be great. [1]: https://millsp.github.io/ts-toolbelt/modules/any_compute.html https://millsp.github.io/ts-toolbelt/modules/any_compute.htm...
- deleted 4y ago[deleted]
- darepublic 4y ago> Types add a lot of code to your library. When first attempting to contribute to a project, one must grok the application logic as well as the type logic. To me types are very welcome. It's much easier to grok a function when I can see a type interface for it. Some libs do this better than others. Some libs have types as an after thought and you get confronted with something like: ``` export type Parameters = {[key: string]: any} ``` which is basically a giant FU and is as helpful as no type. But to me, well maintained type api is a great boon to both contributors and end developers.
- lucideer 4y agoTypescript is bad for library developers who have produced bad[0] APIs and don't want[1] to refactor them. Overloads exist in Typescript because as a language it needs to support what javascript supports - regardless of whether the pattern is "good". Overloads are heavily used in DefinitelyTyped because contributors there haven't had the luxury of designing the APIs they're typing. If you're designing your own API, you shouldn't be heavily using overloads because typed languages don't encourage the ridiculous trend of movable arguments that jQuery pioneered in the JS world. Similarly, if you're writing all of your own code you shouldn't need type manipulation because you shouldn't be leaning heavily on variable mutation. Dogmatic stances on immutability are reasonably a matter of debate, but it's fairly uncontroversial to state that minimising mutation in your data flows helps prevent your code becoming an unmaintainable mess. Etc. [0]Writing good APIs is hard - bad APIs are inevitable. Typed languages make refactoring faster. [1] Refactoring untyped languages is very hard and the tendency not to is deeply ingrained and very natural/reasonable.
- ajkjk 4y agoThis, 100%. In this very comment section there are a bunch of people saying "I maintain <API with crazy unnecessary complexity in it> and I can't figure out how to translate it to TS". Well yeah, that API sucks, make a simple one instead.
- 4y ago
- tannerlinsley 4y agoTLDR: I write and maintain several good-sized typescript libraries so I write library types all the time. In fact, I'm writing them right now! TypeScript is what makes them really fun to use. They infer everything they can and have very high levels of safety and passthrough while still allowing for composition and extension at the framework-adapter and library level. I will never consider writing another OSS tool in the JS ecosystem without ensuring the typescript experience is the best I can offer. That said... I've learned that "library" types might not be the best way to talk about these concepts. What we're really talking about here are types that are complex/advanced enough to force you to venture beyond the primitive building blocs in the TS docs and into existing open source solutions that have trail-blazed more advanced use-cases. It took me only a few weeks to get comfortable with common TS, but at least a year to feel dangerous enough to write more advanced TS. I'm on year 3 now and I am still learning/forgetting so much about it. I agree that: - Advanced types and their concepts are difficult to learn. - There is limited documentation on how to create/use them. - They can sometimes be difficult to reason about, mainly due to the limited syntax TS offers around advanced concepts. On the the positive: - They can be learned with practice. - There is plenty of OSS out there to learn from - Once you learn them, you start to think differently about TS as a language instead of annotations I wish there were better features/syntax support for: - Optional generics - Higher-order generics / Polymorphic generics (basically higher-order functions, but for types) - More built-ins (like ts-toolbelt, type-fest, etc) I think this ramp of difficulty with advanced TS types is fine for the most part. Library authors have always carried way more of a burden than devs at the edge, even during runtime to ensure things like size, performance, flexibility, etc. TS is just another facet that is becoming more an expectation every day. At the end of the day, a library dev gets to choose what level of investment they'll put into great types for their library. If they can pull it off, their tool will likely provide a measurably better developer experience. That's my goal for my libraries, so choosing to go all-in on advanced TS is now a no-brainer. Anywho, good luck!
- harrisonjackson 4y agoI don't depend on the actual typescript docs much but thankfully in @types and in tons of repos there are examples of well written typescript code. The amount of JS and TS out there is also a bit of a foot gun though so stick with heavily used/starred libs if you aren't sure. One tool that helps a lot with developing libraries in typescript is TSDX[0] or its successor dts-cli[1] and there is a bunch of good stuff in awesesome-typescript[2]. Maybe library devving is harder?(more work?) with tyepscript but it is worth it for the end developer, especially if that end developer is you. If you aren't using your own libs then you're probably getting paid by someone else to make them or... idk. [0] https://github.com/jaredpalmer/tsdx https://github.com/jaredpalmer/tsdx [1] https://github.com/weiran-zsd/dts-cli https://github.com/weiran-zsd/dts-cli [2] https://github.com/dzharii/awesome-typescript#libraries https://github.com/dzharii/awesome-typescript#libraries
- lucideer 4y ago> Why are there no guides on the typescript site about library developers? What about a guide on the recommended tools for a library developer? I have no idea what this means. What are "tools for a library developer"? > I think the underlying assumption here is that there is no difference between a library developer and an end-developer, which I reject. Expansion on why they reject this would be of interest here. I'm a library developer - I'm not aware of any differences.
- yesimahuman 4y agoThis hasn’t been my experience, certainly not in 2022 with all the progress typescript tooling has made. Testing is annoying to set up the first time but once you have it working you barely ever have to mess with it. As a library author myself I struggled a lot more with monorepo management and changelogs/publishing but tools like turbo/nx/changesets have really helped here.
- simonsarris 4y agoI am really surprised by this guy's opinion. I make GoJS (https://gojs.net/ https://gojs.net/), a diagramming library written in TypeScript with 68k weekly downloads on NPM. The project began in 2011 and we converted it to TS in 2018. It's been a huge plus. The sole downside was the initial time it took during conversion, but even in doing so we caught bugs with incorrect input types, documentation mistakes, bad range enforcement, etc. On our end, it enforces type safety better than the Google Closure Compiler. There has scarcely been a problem with type complexity that was not ultimately our fault. Just a couple minor things that TS amended later. For that matter the TS experience has only gotten better, generally. On our users end, we can now give them a .d.ts file that's much richer and easier for us to produce to aid their autocompletion. And we can use that .d.ts file to ensure that all the methods we intended to expose/minify are getting exposed. The advantages with the .d.ts and documentation make it feel almost essential to me for library developers to consider TS. TypeScript has only made debugging easier, much easier since it catches errors at time of typing unlike the closure compiler. The sole exception is that debugging is a bit slower since I have to transpile instead of just refreshing the browser. But I have tsc set to compile a relatively unminified version of the JS. But if the slowness gets to me, I can just edit the JS output until I solve the issue, and then carry those edits over to the TS. This has never felt like a problem, though maybe his library is significantly more complicated. It is very possible that my opinions are colored by using the Google Closure Compiler for so many years for type enforcement, long before TS, which has forced a level of discipline that may be unusual to JS programmers. But it seems like the problems are not with TS, but with the labors of architecting coherent and consistent APIs. But I am not familiar with the author's work to really judge. Feel free to ask me anything if you have questions about library design + TS.
- azangru 4y agoTerrible as opposed/compared to what? Maybe a language with better type guarantees would be better suited for library developers; but if the alternative is plain javascript, then no. Just no.
- cellis 4y agoI just wrote and published a library and CLI (for migrating postgres databases) to NPM using Typescript ( https://npmjs.com/package/nomadic https://npmjs.com/package/nomadic ). The Typescript itself, coupled with jest TDD made development very pleasant. The hardest part for me was figuring out how to publish the types so when a user installs it using yarn install, they get Intellisense. I think I did a poor job of it, as in the end I just published the source code. Even though I prefer when npm libraries do this ( as I can inspect the source in my editor easily ), I know the pros don't do that. If anyone wants to take a look and knows how to solve this type publishing, I'd be very appreciative.
- acemarke 4y agoGlancing at it very quickly via Unpkg, I _think_ you really just need to fix the broken `types` path reference in `package.json`. Right now, your `dist` folder has `dist/index.d.ts` available, but `package.json` points to: "types": "./lib/index.ts" Just change that to: "types": "./dist/index.d.ts"
- olliej 4y ago> There are a lot of reasons why typescript sucks for library developers, but at the end of the day it reduces developer productivity. In effect, we are shifting complexity from end-developers to library developers. Yes. The point of making a library is almost entirely to take the complexity load from developers.
- kansface 4y ago| How do library developers debug their highly dynamic and heavy use of conditional types, overloads? Don’t write that code because it’s impossible to debug and test? If typescript yields pain here, it’s appropriately felt imo.
- rowanG077 4y agoI don't have written much TS but the author's experience is exactly what I felt while writing TS. The bolted on "gradual" type system makes typing harden then even dependently typed languages I have used. I honestly believe TS has done irrecoverable damage to the perception of types to millions of web developers.
- jasonhansel 4y agoEven better: because of TypeScript's many known (and unfixable) soundness bugs, adding types doesn't even guarantee that there will be no type errors at runtime.
- brap 4y agoThe examples they provide from Redux are insane, and they’re saying it’s “types done right”? What is it about TypeScript that you get these insanely verbose types? I have never seen anything remotely like this in other typed languages e.g Java. Maybe lack of overloaded functions?
- acemarke 4y agoHi, I'm a Redux maintainer. As my co-maintainer Lenz Weber just said on Twitter: > No other language I know allows us library authors to have that much influence on autocomplete and dev experience. We could all just ship mediocre types with some added runtime exceptions, like we are forced to do in other languages - but we see this opportunity and we go for it. We are not forced to do that, it's the same masochistic drive that makes us write the lib in the first place. We've deliberately done a lot of work internally to make sure that our end users _don't_ have to write very complex types in their app code. As I mentioned in another comment, the linked `createAction` example is specifically representing an object that looks like `{type: string, payload?, meta?, error?}`, and strongly typing the possible combinations of which fields exist. The net result here is that depending on how you've defined your reducer and action, when you type `action.` in the editor, you'll get correct autocomplete listing exactly which fields _do_ exist based on this specific action type. Normal app code won't have to write anything like those types.
- brap 4y agoIn something like Java this could have been solved with method overloading, e.g: ActionWithPayloadAndError createAction(String, Payload, Error) If I understand correctly, overloading doesn’t exist in TS.
- 734129837261 4y agoTypeScript has come a long way, but one of its biggest issues is the complete lack of FORCED sensible naming conventions. Generics are the worst offender, with people often using a single letter to represent something that's both hard to keep track of and impossible to intuitively make sense of. Any type should be: `TUser` and not `User`. Any generic should be: `<GPerson>` and not `<P>`. Any interface should simply not exist because it's TypeScript, not InterfaceScript. The addition of classes into JavaScript was unnecessary sugar and they should just do away with it. So, `type` for everything, no more `interface`. But that's a whole different subject. I've also noticed that people over-engineer TypeScript. I had a team mate telling me he wanted to make URLs type-safe. I asked: "But why?" and he had no answer. There was no problem preceding it. There wasn't anyone asking for it. It wouldn't solve something we didn't know. It would just make the codebase more confusing to deal with because, in his solution, there wasn't a single place where routes were defined. Nope, routes would be inferred from Pages and their use of Page props. It was genius. But it also was over 2000 (two THOUSAND) lines of code that I didn't feel like I wanted to deal with. I gave him permission to publish it and get the open-source community involved. Once it's tried & tested over the course of many users and lots of time, we could consider it. He wasn't happy. He was also not very pragmatic. TypeScript seems to do that to people. The "never any `any`"-crowd is so tiresome.
- erulabs 4y ago> It was genius. But it also was [...] code that I didn't feel like I wanted to deal with You sound like a sysadmin my friend! This is exactly how I feel about plenty of software that I've allowed into production, but that now keeps me up at night and distracts me from spending time with my kids. One of the most useful things about plain JavaScript at this point is seeing if it causes genuine disgust. It's a razor for idealism versus pragmatism.
- schwartzworld 4y ago> The addition of classes into JavaScript was unnecessary sugar and they should just do away with it. Weird. Classes are one of my favorite features, even before using TS. I do a lot of data modeling using functional techniques and the class keyword allows a really intuitive way of encapsulating things.
- robocat 4y agoStrong typing is most useful when used for library code. Users of libraries can make their code as dynamic as they like. Edit: I think their complaints apply to library development using any language with types e.g. complex C++ template foo is most useful for libraries? There is little in the article that is specifically a problem with TypeScript. * Good autocompletion. Great for developers using a library. Somewhat self-documenting. * Narrows down origin of errors. Great for library users and library developers. Nobody wants uncertainty or finger pointing. * Typing is a strong API contract. Breaking changes to the API are more likely to break existing code. That is absolutely good from the library user’s point-of-view. If a library developer wishes to deploy a highly dynamic API for their library, they can just use “any”, but expect most developers to dislike the library. Planning your types correctly, and designing the API carefully to use types, does cost library developers a lot of time and thought. But the library users get outsized gains because library users usually hugely outnumber library developers. > we are shifting complexity from end-developers to library developers. This places a huge burden on us to be experts with how typescript works. That is to be expected. Good library code is hard to write. It would be lovely if there were better resources to help library writers, however it is a specialist role since library users usually strongly outnumber library writers. It appears to me that many of the design decisions in TypeScript for the type system are there to help library developers. Patterns of usage were recognised and then added to the type system. Disclaimer: not a TypeScript library developer.
- Bellend 4y ago"I don't know how to make my library typesafe so everyone else is the problem". It's a fucking boring topic that has been done to death since 2012. Get this deleted guys.
- Loeffelmann 4y ago> It's pretty common in style guides to never nest ternaries. In typescript, that's the only way to narrow types based on other types. It's a mess! I really wish there was a kind of type builder where I can use ifs and switches to build complex types. For me that would already take away a lot of the pain of maintaining and writing complex types.
- nichochar 4y ago>In effect, we are shifting complexity from end-developers to library developers. This places a huge burden on us to be experts with how typescript works. Interesting, I had never thought of this tension, but I think I disagree with the author and think this is a good tradeoff. We shouldn't assume all developers are library developers, most beginner developers for example don't write libraries or shouldn't. I think it's actually good to force competence in the library author domain (within reason), since they can abstract away this pesky complexity (the point of any good library). I like this new mental model, but I still agree with the author that typescript is too hard to work with and developer experience with it has a ways to go.
- bigbillheck 4y agoI'm not a ts/js person but > we are shifting complexity from end-developers to library developers this is exactly the point of a library in any language. The library authors do the heavy lifting precisely so that the end-users don't have to! And again, this isn't my domain, but when I read stuff like > How do library developers debug their highly dynamic and heavy use of conditional types, overloads? or > Because types can be generated from other types and the highly dynamic nature of those types, there's a new class of tests that are required for any serious typescript project: testing your types. or > I spend more time tweaking types than I do writing library code. what I'm thinking is "Doctor, it hurts when I do this".
- simlevesque 4y agoIf your library was built without thinking about types, yeah it'll be ugly when you add them after.
- deleted 4y ago[deleted]
- rhacker 4y agoI'm quite surprised when I see a title like this and the page isn't full of ads. I would expect such a click-bait title to be jam packed with ads.
- qudat 4y agoI regret the title now but that ship has sailed.
- armchairhacker 4y agoFor me I use and rely on types a lot. A good type system means I write code in less time and effort, otherwise I wind up with runtime type errors and sometimes comment in my types anyways. So I have the opposite problem: as a library user, JavaScript is terrible for me, because even when I use TypeScript I get runtime type errors from bad type declarations or even just holes in the TypeScript type system.
- coryvirokmobile 4y agoI hate to break it to you, but every single piece of technology you use depends on a library that is strongly typed. Without strong types, there is no contract you can depend on. Imagine if every .so/dll/exe/obj/a file exported void* pointers as their inputs and outputs. That would be mayhem.
- winrid 4y agoYou mean like the Enlightenment Foundation Libraries[0]? [0] https://what.thedailywtf.com/topic/15001/enlightened https://what.thedailywtf.com/topic/15001/enlightened
- jongjong 4y agoThere is a good reason why dynamically typed languages have such large and vibrant library ecosystems compared to statically typed languages... I've been saying stuff like this for years. My main problem with TS is that it tries too hard to shove itself down everyone's throats and just seems to be destroying open source along the way. All these complex (albeit well-defined) interfaces add friction between libraries. Imagine that you're an electrician and your job is to change a lightbulb... Do you really want to have a meeting with the central standards committee and the lightbulb manufacturer in order to be able to change that lightculb or you just want to screw it in and be done with it? The core problem with these type systems is that they try to create a globally-consistent universe where all the different modules/libraries agree about what all the different types which might exist in the actual universe are but somehow they never manage to get there; or if they get close, they end up extremely rigid and require a lot more effort to maintain (E.g. Java).
- mirekrusin 4y agoI think you're conflating object-orientation with algebraic type systems (which java doesn't have).
- jongjong 4y agoIn Java, there seems to be an interface for every concept and the way they are used is quite restrictive in a harmful way. For example, a URL isn't merely a string which is copied/cloned (by value) each time it gets passed to a new function, there is an actual URL instance and you are encouraged to pass around references of it. This type of design can cause issues if multiple modules end up holding a reference to the same instance and try to modify it (in conflicting ways). It just encourages poor design IMO. It requires more effort (more friction) to avoid bad, tightly coupled architecture.
- STRML 4y agoOh, man. This hits home. I wrote a bunch of libraries for public consumption with Flowtype - Facebook's competitor to TS, which was dominant circa 2016 - and there was very little on "advanced types" available to us. React types ended up being a massive pain, from the banal (React.Component vs React.Element) to the crucial (how do you represent the required props of a component, when some subset of them are being injected via context?) Like the author, I used the redux code heavily to figure out what I needed to do, but it changed often and it seemed like the authors were also discovering the best way to use it. Combine with a bunch of Facebookisms (they were literally called that inside Flowtype source!) that were half-baked and... yes, we were just doing trial and error to make our typedefs succeed. Add onto that a severe weakness of Flowtype, its propensity to coerce to `any` without telling you, making your types green but masking real errors and... it was a time. A time with a pain quotient in the neighborhood of doing async module loaders in 2012, or cross-browser DOM manipulation in 2008. It seems, we always find a new problem to tickle our brains.
- acemarke 4y agoI'm very curious, which "Redux code" are you referring to here? I don't think the `redux` core lib ever shipped any Flow types itself. Looking at the FlowTyped repo, I see community typedefs at https://github.com/flow-typed/flow-typed/tree/master/definitions/npm/redux_v3.x.x https://github.com/flow-typed/flow-typed/tree/master/definit... , and the Git history suggests those were indeed written by community members. (of course on the flip side, _I_ didn't even start learning TS myself until 2019, and goodness knows _that_ has been a lot of trial and error over time :) )
- brian_love 4y agoMy colleague posted an interesting article that addresses the disparity between an end-user of a typescript library and being a library author. As the user of a library, not only do I hope for excellent documentation, but I also hope that the library authors have designed an ergonomic API that provides clear and consistent typings when using TypeScript. What I acknowledge I lack is a clear understanding of the level of effort that is required. Designing and building a library is challenging, creating documentation takes time, and support TypeScript types is another burden that I place on library authors. Check out the article: https://liveloveapp.com/blog/2022-08-23-overcoming-typescript-type-challenges-for-library-authors https://liveloveapp.com/blog/2022-08-23-overcoming-typescrip...
- eternityforest 4y agoLibraries are where the complexity should be. It it's used by 200 people, it makes sense to put the work in there, rather than duplicate it 200 times. Library developers obviously deserve nice things too, but that is why they should be getting paid for their work. If TypeScript is better for users(I think it is, although I would prefer we move the whole world to Dart natively with no compile step....), then it helps you make a better product. Which you should be getting paid for, as many FOSS devs are.
- chucklenorris 4y agoThis article made me laugh. I worked and am working with new typescript developers in my day job. They all go through the stages of typescript grief. - Denial - This should be pretty easy, just put types everywhere! - Anger - But my code is correct! The damn compiler doesn't understand what I mean! - Bargaining - Can't I just use any? - Depression - This will take forever to figure out and I have a deadline :( - Acceptance - It's a tool like any other, it's a hassle, most of the time is useless but sometimes it saves you from bugs and makes collaboration easier. You just have to accept that the type specification in typescript is a whole separate language that you have to learn, that takes time to write correctly. In my experience that's at least 30% more than writing js when you know what you are doing, more when you don't. Adding the linter and tests you end up spending more time on these correctness checks than actually writing code, and that is ok, or not, depending on the project goals. When you are writing library code this cost goes up, WAY up because your library will be used in multiple ways by different people so you have a combinatorial explosion of cases that need to be handled. I don't understand where this expectation that writing typescript should be as easy and quick as writing js. IMHO the typescript docs are one of the best resources (just compare them to python docs...)
- bblaylock 4y agoThe primary issue I have with this article is that it points to redux-toolkit as having types that are done right. The same result of redux-toolkit create actions (https://github.com/reduxjs/redux-toolkit/blob/4ab8c42cb20ae1e6f7b84a8ac0070eee54775b79/packages/toolkit/src/createAction.ts#L58 https://github.com/reduxjs/redux-toolkit/blob/4ab8c42cb20ae1...) can be made mush simpler (see https://gist.github.com/baetheus/2e16ad4118b6fcd45e45756780ebb22a https://gist.github.com/baetheus/2e16ad4118b6fcd45e45756780e...). The only real difference between these two implementations is the simpler one doesn't overload a single function with multiple strategies for datatype creation. In my opinion, our industry is not generally exposed to type level programming or dependent types. As a result there are many popular APIs (redux, redux-toolkit, react, vue, jquery) that implement variadic and generic interfaces with many overlapping options on single functions. If the types for these interfaces had been written (or long considered) before being published then the authors' might have noticed how complicated they are at the outset and perhaps decided to solve the simpler problems first and build the complexity slowly. "It is a poor workperson that blames her tools"
- cheeselip420 4y agoThis sounds like someone who is trying to write Javascript libraries instead of Typescript libraries. While Javascript has nothing to do with Java, the same cannot be said for Typescript and types...
- mdwagner 4y agoDon't listen to HackerNews folks here, you've validated a lot of the issues that I've experienced as well. No one here is taking you seriously, because they're trying to put the blame on you, but it's not you, it's TypeScript. The solution is not to switch to something else, it's to put pressure on TypeScript to make this quality of life better.
- janpot 4y ago"we are shifting complexity from end-developers to library developers" that is the exact reason why I use external libraries.
- perryizgr8 4y ago> library developers > This places a huge burden on us to be experts with how typescript works. Yes, exactly. That's how it is supposed to be. You need to have expertise in the programming language to be able to effectively develop libraries other developers will use.
- miffy900 4y agoMore people commenting here need to pick up on this; this is how it's supposed to be. The author also mentions: > In effect, we are shifting complexity from end-developers to library developers. This is not a valid complaint. This is obvious and self-evident; and also true for any lib developer in any language - you can't avoid it. Libraries exist to abstract away complex logic so those devs consuming the library don't have to worry about writing their own implementation - an app can delegate functionality to a library and this has the benefit of reducing the app's maintenance burden and speed up dev time by re-using another developer's work. And for lib devs, this inevitably requires they spend effort to make their library easier to use.
- mostlylikeable 4y ago“In effect, we are shifting complexity from end-developers to library developers.” For me, this should be a principle goal of someone writing a library. A primary function should be to shift complexity into the library, and allow other developers to not have to worry about it.
- forty 4y agoI read the article as "I'm not experienced with TS yet and learning is not as easy as not having to learn something" :) Good news is that it will improve as you use it ^^ I don't get the point at all of the difference between app and library developpers. Any app of non trivial size will have some kind of internal library and thus any app developer is a library developper too.
- tekkk 4y agoA bit click-baity title but as I read the article, I agree on the overall thesis. The lack of documentation on how to use types is really annoying when you start going deep utilizing generic types and whatnot and bumping into weird errors. Like for example, I wanted to type a generic object you can persist to a localStorage. What's the correct type? Can't use an interface if you make a recursive type so you need a type. But if you use a Record<string | number, Persistable> and your client has some regular interface APIResponse { foo: string, bar: AnotherObject } the types dont match. I forget the specifics, but I ended up using { [key in string | number]?: PersistableValues } where PersistableValues includes all the primitives as well as arrays, sets, maps etc which I serialize/deserialize on persist and hydrate. Using `object` as type is listed as bad-practise in TS documentation which I agree but really, typing all the handled cases by hand is not fun either. Wonder if I just should use any and throw an error if I encounter something I am unable to serialize.
- hamandcheese 4y agoThere are two main reasons I see types become complex: First, and most related to TypeScript, is that the library predates TypeScript and the dynamic nature of JS made it easy to create much too complex interfaces. Second is when a library is very frameworky rather than a less opinionated library (I see this sometimes in Sorbet types written by my colleagues, even for greenfield stuff). Don’t want to make a value judgement on either, but it’s certainly possible to write useful libraries with simple types. Look at golang.
- SSchick 4y agoThe idea that some developers think their code is so smart/complicated it cannot possibly expressed in a statically analyzable manner is pure hubris to me, JS/Python and friends sure have encouraged some bad patterns over the years. Sure it has a learning curve but I see highly flexible strictly typed as the medium-term future of pretty much all development as they provide invaluable safety nets for development, risk mitigation and productivity. Large code bases without strong rigor,testing and/or static type analysis (eg. mypy/ts/flow) have no future and will not scale.
- random_savv 4y ago> I think the underlying assumption here is that there is no difference between a library developer and an end-developer, which I reject. There is - developing good libraries requires a much higher standard than developing good frontends. > In effect, we are shifting complexity from end-developers to library developers. This places a huge burden on us to be experts with how typescript works. That is the main purpose of libraries: to take work away from the user of it.
- crowdyriver 4y agoI just don't understand why library developers must make extremely complex APIs then. Does it really need to be so dynamic? MaterialUI v4 types where so huge it slowed down all my type checking, rendering typescript productivity useless.
- dcow 4y agoOnce Rust finishes up the DOM interface types effort we can just write everything in Rust, which is well documented and great for library authors.
- t_tsonev 4y agoThe TypeScript's team decision to ship breaking changes in minor releases surely doesn't help library authors. Breaking changes are introduced way too often and the compiler can't output backwards-compatible types.
- Lapsa 4y agoTS is one of the biggest fish on my skip-list
- unemployable 4y agoEverything in this article is true. As you can see by the comments in this thread, saying "I love TypeScript" is not enough to please the TypeScript cult. Nothing but complete devotion is required. You can say "it has its flaws" but don't mention them, just say that phrase to pretend you aren't biased. The comments in this thread say that the way you are writing TypeScript is wrong. What they are advocating for is essentially turning TypeScript into Java in terms of its style. This is what good TypeScript codebases end up looking like. They don't look like JavaScript. You could take all of the type information out and they still wouldn't look like JavaScript. I think that when people find that their ex-JavaScript, now TypeScript codebases have become Java codebases, many of them will realise they don't really like TypeScript anymore. If they are the people that said "You aren't professional if you don't use TypeScript", etc, then they are not welcome back into the JavaScript cult. If they are not one of those people, they must profess their hatred of TypeScript, and then we will let them back in. Anyway, no matter what, you still have to work with the native APIs and so on, which just don't work with TypeScript. Take Web Components for example. You create a web component by defining a class, but you never instantiate the class yourself. You use document.createElement('my-component'). Good luck typing that. Good luck typing proxies. I hate TypeScript.
- edem 4y agoAs someone who has written libraries int other languages as well I have to say that library development in Typescript is awesome. Library development in general sucks. You just have to do a lot more things compared to product development, it is not Typescript's fault. Also, I've never had to use conditional types in my life. I think you're over-complicating things.
- KronisLV 4y ago> I spend more time tweaking types than I do writing library code. This was basically me in a TypeScript React project, except that instead of being able to quickly iterate, instead I had to spend bunches of time messing around with types. Of course, you could also say the exact same thing about using Java vs something like Python (though it has type hints available, of course; not that all codebases take advantage of it) and then have a discussion about what you think about strict type systems and where (front end/back end/DB) they're useful to have and in what capacity. I guess it's one of those topics where thoughts differ, much like how some people might place a lot of emphasis on unit tests instead of integration tests, or even just (primarily) test the back end instead of bothering with front end tests, due to how much harder they can be to write, depending on the codebase.
- wruza 4y agocreateAction #1 #2 This is a disaster part of typescript that will doom you all. Through years and languages I made an observation, and it is: If you give a way for smart people to create a horrible mess, they will internalize it eventually. Sendmail.cf, template meatprogramming, #define hell, etc. Typescript “type manipulation” is one of these ways. It may seem very cool that you can define base types and then extend and reshape them in derivatives all you want. But types are not about solving puzzles in one go declaratively, they are about helping developers to understand which code may be incorrect. There is nothing wrong with declaring all the derivatives by copying type code and modifying it, because if there’s inconsistency, it will be caught later in tests, in interfaces, in your own code. Yes you create a dynamic structure of types, but it goes beyond human limits to understand or debug it. One way to fix that is “type assertions”, based on the same principle. E.g. instead of declaring type B as a programmatic derivative of type A (and/or/with dozen of type metaprogramming routines), you just write B as it is and then assert that B maps to A as designed. Or make an IDE do this for you automatically. These assertions will still be hard to read, but the resulting type B will remain both understandable and correct. Also, separately, please stop making polymorphic interfaces like “if you pass an object with key X after an object with key Y, that means mode of operation A, otherwise it’s mode B unless there is an array of numbers before the argument of type T, then it’s mode C”. They may look cool in readme.md, but are hard to remember and work with on both sides of an interface.
- michaelcampbell 4y agoIME... > I spend more time tweaking types [to gain confidence that my code is actually doing what it should] than I do writing library code[, which would probably be wrong, and saving time not having to write type-based tests]. I don't know what to say here; I've had types save me from a lot of blunders. If nothing else it moves my debugging/fixing time "left" in the timeline before it hits production. Maybe that prevents me from getting code out as quickly, maybe not since there are then that many tests I don't have to write. Maybe he's just a way better dev than me too.