Figma’s Journey to TypeScript
figma.com
figma.com
Seems to happen a lot though. Company makes custom stuff early on, gets big, then migrates to something "standard".
Then a few months ago I decided to write a TS project from scratch. For the record I have 18 years of JavaScript experience. What I found was that the biggest barrier to entry was configuring webpack to be "just right". Other devs on my team with similar level of experience would have their eyes glaze over when webpack came up and get annoyed. For good reason. It took me several days to get it to work right. The fact that the tsconfig has 20 options that can effect the transpiler and not have good docs is a problem. The fact that there needs to be two tsconfigs in a react native project that compiles down to web as a secondary build target is another problem. The fact that you need a very experienced dev to spend days configuring webpack is another problem. Finding information about the right configuration is like the blind leading the blind. Most search results on the topic are riddled with half truths and non sense. Many devs rely on a preexisting webpack config and if they do anything to mess it up they are many times completely unable to fix it.
Typescript is fine. I guess. The code produced is nicer. But having to rely on webpack is an issue.
I actually like TS but I wish I didn't need to transpile anything or have to bang my head against a webpack config for days. It's by far the biggest barrier to entry because while you're banging your head against it you're not writing code. And for none technical stake holders when you have nothing visual to show at stand ups that can create friction and make the engineers seem like they aren't doing anything.
So far at multiple companies I've had to configure webpack for extremely complex JavaScript based single page apps which took me literally months of messing around with it until it worked just right. And until it does work "just right" the non technical folks think you're wasting time.
As someone who has just spent a whole week trying to plumb Vite + Rollup into an ASP.NET web application, I can relate to this on many levels.
I can produce 90% of our functionality with vanilla javascript + a sprinkling of JQuery, but to get something 'modern' in Vue.JS fitting into the application comfortably is a bloody chore. Sparing the gory details, it feels like orchestrating a thousand moving parts while being blind with a gun named 'ship or die' held to your back.
For comparison, the EF core at least gives me logs. C# is a delight to debug. Print statements can tell me what I need. These parts feel wholistic.
Yet the web stuff is just so scattered, so much to configure, so many options where if you want to do something even slightly non-standard you are in the dark, mashing the conf files until it works and you aren't even sure why but you have to move on.
This feels different from mastering one language, even though it has a steep learning curve. I hit roadblocks in perl but they weren't as frustrating and it felt like everything was feeding back to a cohesive whole. With webdev, it doesn't feel like that at all. I don't know why, I wish it wasn't so.
All the pieces exist to make it work, but you won't find much documentation to help you. You'll have to rely finding blog posts, but of course if the post is more than a year old most of the libs or tools they're talking about will have totally changed. Once you do get everything up and running you'll often find that the dev experience is less than great.
They do fundamentally the same things but with very different approaches and tradeoffs.
Webpack and Vite are very different approaches to the same problem with different tradeoffs[0][1]
[0]: namely, webpack and its inevitable successor rspack, are way more flexible and arguably powerful but at the cost of higher complexity and more proprietary features like the webpack/rspack specific runtime. Superior in asset handling though, in many respects, and the high level of optimizations you make once you hit a certain complexity threshold is greater than what Vite/Rolluo has currently without extensive custom plugins
[1]: Vite or Rollup is most likely what most projects need. I’d recommend always starting there, as most of the advanced and flexible features of webpack/rspack are very much not what most need
Between the various TypeScript module options and various package.json module options (and various code patterns used), modules make JavaScript way more painful than it should be.
I think most of the JS language standards work the past 10 years has been awesome, but modules was definitely rushed and poorly thought though, causing years of frustration.
- SSR rendering of react in an express app (both typescript).
-Trying to get VSCode visual debugger to work for both the client and server code paths.
- Getting the various test libraries to work correctly (I still can’t get the NYC code coverage library to work).
- Mix of ESM, CommonJS, misconfigured npm packages that don’t expose their types correctly.
I ultimately used Vite, and got things working 90% the way I wanted and called it good enough.
On the Vue vs React debate, honestly it comes down to preferring templates vs components. Vue is simpler but there are good reasons for a lot of the React complexity, and React still has a stronger ecosystem and more developers.
Remix is moving to Vite as its default compiler. https://remix.run/docs/en/main/guides/vite
My project is relatively tiny too. I’ve never regretted a choice more than Remix.
It leads to scenarios where I receive OpenApi specs that loom like this:
type:
- string/integer
They just don’t give a shit because this kind of crap works in PHP.They could use:
oneOf:
- type: string
- type: integer
Which is nastier to deal with a typed language client, but at least it conforms to the spec.So thank you for actually caring about types in PHP.
I’ve done Webpack configurations and Browserify before that. I’ll be glad if I never go there again.
I’ve been using remix for the last 6 months and I’m super happy with it.
Next really fucked up with the app router, and people are realizing everything is just a trap to get more customers on vercel.
As soon as you hit an edge outside of their matrix of management you open the dark Pandora box of front-end development.
As a corollary, though, I think those kinds of cultures are only possible if your team is composed of primarily brilliant people, because these brilliant people can move faster than most competitors even if they do wander down an unproductive path for a while, and there is total trust that the folks on your team are capable and self-motivated.
Then comes a point where the community catches on and has bigger momentum than the company, so it makes sense to move to the standard implementation.
I'd kinda see Google's Borg -> k8s move as slightly similar, though they're the one inviting the community around the standard they built themselves.
Now they also have modern PHP and some other languages alongside with hack from what I understand.
https://medium.com/@aarthimanikandan2006/does-facebook-still...
PHP and its community were dying by the time FB used it. People here on HN kept talking php down.
In 2014 FB made their own flavour of php with a bunch of perf features, called hack.
Eventually a lot of the perf features hack made its way into php.
FB is still on its own flavour. Php community is still dying.
But maybe the php forums + guestbooks was what you had in mind with 'php community', in that case you have a point. Most of the kids have moved on.
The popular frameworks are still growing steadily and WordPress is starting to slowly shift off some of its stranglehold on old versions now that most webhosts don’t even offer old versions. That said, even Wordpress will work out of the box with old versions (they just don’t write new features against new PHP versions).
This is arguably the most exciting time to be a PHP dev!
I've started to learn the ecosystems of the other languages. It's all the same shit. Really.
I used PHP to run some service workers managed with supervisord and it was fine. I just get annoyed with the class-based hierarchy but I'd guess they've evolved since 2017 or whenever I used it last.
To me, what PHP needs is a simple module system with scoped functions and variables, an object literal syntax rather than `new \stdClass`, and first-class simple to use threading/async/promises for concurrent requests and IO.
The worst thing about PHP: shared nothing architecture.
It works extremely well until it doesn’t really scale anymore.
There's still a ton of stuck that could be fixed, and php will always be talked down in some way or another but I don't think it's in a bad position as it is now. There's pretty significant code bases newly built on php right now, even if it's not making the headlines.
> Php community is still dying.
https://www.tiobe.com/tiobe-index/php/
https://w3techs.com/technologies/overview/programming_langua...
Yeah I dunno about that one.
Want a real example? Everybody knows that Instagram runs Python. But https://w3techs.com/sites/info/instagram.com can't tell which server side language it runs. There you have it.
I would not use the number unless it can be validated, rather than use it simply because it's "the best we have". No, it's not even remotely good.
If you can maintain your Unicorn hiring criteria long term, maybe fully custom stacks are maintainable. For most organizations, they need to move to something that the average hire can maintain going forward. That means big name boring software vendors for the most part.
Sometimes it's worth it if the speed boost is huge, or if you can write safer code, or if you actually want to gatekeep hiring to people who like learning new languages.
Like, all those people that chose Flow now have something "non-standard."
(insert canned laughter)
Coffeescript is still better than js with many ideas - everything is an expression, comprehensions, existential operator, extended switch statement, chained comparisons overall terse, readable syntax.
Some things are terrible ie. type annotations through clunky comments.
I have a ton of respect for the language and all of the stuff it cross-pollinated into JS, but it’s an interesting object lesson in how a seemingly tiny design choice can turn out to be disastrous.
I guess when exploring uncharted territory it's a bit of a dice roll - you can't keep winning all the time.
Otherwise great contrib to advance frontier.
Coffeescript was before my time so I never used it, can you give an example of the problems this caused?
So what can happen is that you have some large block of code where, for example, near the top, you’ve said “x = 1”. Then, maybe a few hundred lines down you have a loop, and inside the loop you say “x = getWidget()”. You think you’re declaring a new variable, but actually you’re reusing a variable from the outer scope. There’s no way to know if you’re accidentally doing this except to search the entire enclosing scope.
It’s even worse in the other direction. You have a small block way down in a function where you’ve said “x = getWidget()” and this is all fine and correct. But you need to add something to the top of the function, and you add “x = 0”. You’ve now retroactively changed the scope of some random variable you weren’t even thinking about.
Edit: Actually my memory’s a little rusty, but I think they actually removed any kind of block scoping entirely by version 1, but everything I said above still applies to nested functions, which you tend to use liberally in CS.
JavaScript has had this for a bit now and it is really nice.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
if window?
env = 'browser'
...
is equivalent to: if (typeof window !== "undefined" && window !== null) {
env = 'browser'
...
}
But yes, nullish coalescing and optional chaining that came from existential operator are good.Also, was Typescript really as claimed in its "infancy" at the time mentioned in the article? They didn't mention a particular year.
I don't follow. Where did I do this?
"Smell" has negative connotations in English. If you say that "this code smells" it means it's bad, and likewise it's very easy to read your "It does smell like" as you meaning it's a bad thing.
Custom is great right up to when the lead eng leaves.
The title of the post is misleading because we used Typescript at Figma for nearly a decade in other parts of the codebase, and there was more Typescript than Skew for almost that entire time. As the blog post explains, Skew was used in our mobile engine (and eventually for our prototyping player, mirroring feature, and maybe one or two other product surfaces I'm forgetting).
According to Evan Wallace (former Figma CTO), it was 1.5x to 2x faster due to better optimizations enabled by stricter type system.
It's also what JITers like V8 internally do, you'll get major performance hits if you do weird dynamic things.
If you can leave the type system in place, then you could move toward an ML-style type system and see massive improvements within strictly-typed parts of the code as you'd only need type guards and inline caches at the boundaries of the strictly-typed code.
Only if your code was pure number crunching.
Normal code can't just go through some belt tightening to become WASM/asm.js code. Compiling it down that way is very different from making the control flow more understandable to the optimizer.
My guess is mainly the integer optimizations. And I guess making sure that functions are always called with the same argument types. The other optimizations is already done by the JITs.
It's probably not as simple as that. If hotpaths are optimized, the 2x advantage is quite likely to vanish.
But then one could say - well, you're forced to write optimized JS in several places and that impacts readability. Sure, but the trade off was to use an entirely new compile-to-js language with less tooling support and mindshare. It seems now that it wasn't worth it. The blog post sort of sugarcoats this contentious previous technical choice.
While I'm not going to debate this particular instance, I would caution against assuming all moves (with or without blog posts written about them) are indeed the best and wisest moves that could be made given the situation.
It's incredibly hard to look at our industry at large and declare that teams/companies are doing the best thing they can at any given point (where "best" is defined here as the most prudent thing, all things considered).
I wonder if it’s possible to limit one’s use of typescript to just the subset that gives that same performance…
This is interesting. Why doesn't JS just directly index arrays for destructuring?
> Array.prototype[Symbol.iterator] = function*() { yield 1; yield 2; yield 3; }
> [...[4, 5, 6]]
[1, 2, 3]
The terrible performance of the iterator protocol was discussed and ignored at the time, by saying that escape analysis would solve it [0]. Nearly 10 years later, and escape analysis has still not solved it. It's extremely GC-hungry and still sucks. It's just a bad spec, designed by people who are not performance-conscious.It might make sense for engines to specialize destructuring assignment and splicing of Arrays to remove their iterator protocol overhead (if the user hasn't patched Symbol.iterator) but that's a whole other can of worms.
[0] https://esdiscuss.org/topic/performance-of-iterator-next-as-...
Also, what's even more crazy is that destructuring {0: foo, 1: bar} can be faster in some javascript engines when destructuring an array with two or three element.
- 17M ops/s ± 1.65% for array destructuring in Chrome
- 169M ops/s ± 0.78% for object destructuring in Chrome
- 545M ops/s ± 3.68% for array destructuring in Firefox
- 81M ops/s ± 0.8% for object destructuring in Firefox
So per the principle of "optimize for the bottleneck", one could choose to use object destructuring, because the slowest Firefox is still comparable to the fastest Chrome option. Or when, for example, you're running Node on a server and know which JS engine you're using.
800M ops/s ± 0.5%; 837M ops/s ± 0.32% for Chrome on the same computer.
I wonder if some engineers were sad to see Skew go.
I was definitely sad to see some features of Skew go. For example, operator overloading and integer types. But the move was ultimately a decision the whole team made, and I agree with them that it was the right one.
So Skew only had callbacks?
The very first mention of WebAssembly in the article:
"Some years after WebAssembly obtained widespread mobile support, we replaced many core components of our Skew engine"
Since Figma is also all about multiplayer, I imagine they might have a system that takes changes to a document, packages them up in a compact binary format, and then sends that over the wire (to Figma or to other connected clients). A decent decent target for a WASM module would probably be that serialization/deserialization step.
Sounds like getting stoned and making a meme or something
https://www.figma.com/blog/how-we-rolled-out-our-own-permiss...
If Skew was open sourced maybe it had become a better typescript.
Just because something is open source, it doesn’t mean you get free contributions. Every non-trivial PR must be followed by lengthy reviews, discussions and possibly rewrites.
It's also crazy slow. We're having issues with Zod where it slows down our TypeScript language server performance significantly, so as a result we've had to introduce project references and disable project reference redirects.
All-in-all, there's plenty of work to be done to make TypeScript better. Especially in monorepos, and especially in making it performant.
Your monorepo issues sound like you didn't use the same config in all the packages? If that's the case, enforcing the same config and coding standards would be the first thing I would fix. Again, not a Typescript issue. Or did you use ts-node before tsx? Yeah, tsx is much more robust. It just works.
We’re considering Typebox but it’s a big lift and the author of Typebox, while responsive in GitHub, doesn’t seem interested in improving interoperability and documentation regarding usage with tRPC.
It isn't TypeScript that needs to support your particular set of tooling and library choices, but the other way round. We have a mid-sized monorepo (multiple apps, many services) which is mostly typescript. It works alright with a boring npm workspaces based configuration.
I agree with your assessment re: library choices in theory but it suck to run into these DX problems that you wouldn’t normally run into with other languages, like Go for example.
But it also introduces a lot of extra work "just to appease the type system". It rarely improves performance (if ever). Because TS has no runtime inference/validation, working with larger libraries or the browser can be a chore because half of your code are type signatures or casts.
So - not necessarily a naysayer, but I do believe that TS is oversold and with smaller teams/projects it might be slowing you down as opposed to helping.
every single time it is a reasoning flaw implementing a solution that is sub par and bug riddled. Had they just let types guide them, they would have become better developers and not had broken the application.
I am curious though. can you provide a snippet where types would be a disprovement?
An example of what I call "ceremony" would be
interface BlockIndex {
[key: string]: UploaderBlock;
}
const perServerId = {} as BlockIndex;
uploaderFiles.map((fe) => fe.blocks.map((b) => b.serverId && (perServerId[b.serverId] = b)));
While somewhat useful, this is in internal code which never gets used directly, and there are 4 lines of ceremony for 1 line of actual code.Something like:
const perServerId = Object.fromEntries(uploaderFiles.flatMap(fe => fe.blocks).filter(b => Boolean(b.serverId)).map(b => [b.serverId,b]))
And typescript infers the types correctly. But I still wouldn’t write it as one line, and I’d use lodash instead.my expectation is that there are some packages/DOM typings so you don't need to write them?
regardless, your point stands: typing external dependencies is a pain.
Also Typescript sucks at keeping track of type changes in a single scope. While in Rust I can assign string to foo and then update it with int, I can't in Typescript. This leads to worse types or worse code for the same operation. Combined with typescript's lack of statements as values, conditionally initializing a value is pretty obtuse.
Those are the issues that come to mind right now.
This is literally always your problem with javascript, its only sometimes your problem with typescript. It's a weird argument.
> Also Typescript sucks at keeping track of type changes in a single scope.
Isn't this considered a very bad practice? Also rust does not allow this, it only allows shadowing.
> Combined with typescript's lack of statements as values, conditionally initializing a value is pretty obtuse.
Can you give an example?
For the second one: I know it is shadowing, what I mean is I find commonly that I'd like to have it in Typescript as well. In JavaScript is not necessary since I can just use the same variable.
For the third one: If I have some string variable that needs to be created from either one set of instructions or another, in Rust I do exactly that:
let foo = if x { ... } else { ... }
In ts your options are making it mutable undefined and mutate it inside the if else, using a very weird unreadable ternary, using an IIFE that returns into the constant, or creating extra functions to move the logic out. None of these are even close in readability, locality, or soundness to the rust example.
I find the _combination_ of those things that make it harder to write ts than js.
2: This is a programming practice I never see and would seriously question if its necessary ever, let alone "commonly". I think you may have picked up bad practices from writing in dynamic languages. Please see this for a few example arguments against this practice: https://softwareengineering.stackexchange.com/questions/1873...
3: You are now debating that Rust has better typing than TS, which makes sense because Rust is made from the ground up to have extremely well done static type checking, whereas typescript has to comply with dynamic typing originating from JS. It follows trivially that Rust has the better design because it has more freedom to do what it wants. JS < TS < Rust
it is not really an argument against typescript that Javascript is so bad that you need to spent time tracking your changes.
When do you need to do that? Can you give an example?
Requirements change and the code base needs to adjust with those requirements, that's gonna happen no matter what. I've met a lot of people trying to predict future requirements, deciding to overenginer today for a brighter future. I have very rarely seen anyone guess the future requirements accurately.
That’s not going to negatively affect your initial velocity, if it does, the team isn’t strong enough.
If the project is just a one off website or something genuinely small, sure, who cares? Otherwise it's worth realising that you'll be dealing with the fallout of poor early decisions pretty quickly.
This. Note also that "a poor decision" might as well be "have developers fight the type system instead of delivering UI and pivoting if users don't like it".
Mythical man month in action.
TS often can interrupt an individual's flow, so feels like a negative value. It's only when the whole team is using it on a bigger codebase with lots of changes that the benefits start to manifest.
I rewrote one of those projects in Typescript a while back, and came across a similar "clever" solution (mainly having to do with dates having potentially multiple sources, so being in potentially multiple formats), and it made the code _infinitely_ easier to understand. So much so that when I came back to it recently, one quick glance at the types for that section of code gave me all the information I needed to confidently extend that code without worrying about bizarre runtime errors.
People forget that even in single-person teams, you're actually working with many different "people" over the lifetime of the project, given how different you and your understanding of the context of your code will be over time.
Now imagine you go to a big city where they have a bunch of lines in the parking lot and people only half use them correctly, parking over the lines, diagonal, etc.
The existence of lines doesn't guarantee good behavior. The absence of lines doesn't guarantee bad behavior.
This is the argument I see for javascript-only folks who don't necessary enjoy using "the worlds most bloated javascript linter"
For the record, I am a Typescript enjoyer and I use it in my personal projects as well as professionally, but even I can admit that it's not automatically superior to javascript and it has a number of really frustrating and time-consuming downsides.
It's very easy to type the args and returns of a function and protect callers, but it's much more challenging to work with types between libraries and APIs all together. Lots of `as unknown as Type` or even the dreaded `any` to try and cobble the stack together.
For the record I don't like the syntax either. Combining ES type spreading with TS type annotation makes for difficult reading in my opinion. Why settle for this bastardized language and not just compile something made to be strongly typed into js?
But if you have a dev team that is taking the time to efficiently park in a respectful way, if you paint lines, _you're going to make that parking job a hell of a lot easier to do!_ And THAT's the big win of Typescript.
You're dreading javascript
I don't use it because the compiler is just too slow; waiting 2.5 seconds for even simple files is a massive pain. I want the old "CoffeeScript experience" where you compile stuff on-demand in development and output errors in the webpage or stderr. It works very well, is low complexity, and requires almost no effort. But you can't as it's just too slow.
esbuild doesn't typecheck so it's not an option. And hugely complex background builders are, well, hugely complex, it's not an option.
TypeScript-the-language may be nice, but TypeScript-the-tooling is not particularly great.
And even if this was solved: any build step will add complexity. The ability to "just" fetch /script.js and "just" edit it is quite nice. This is also why I've avoided CSS pre-processors since forever (needed a bit less now that variables are widely supported).
Of course different projects are different and for some projects these downsides are less pronounced. There is no one perfect solution. But there are definitely downsides to using TypeScript.
This is a fallacy similar to the Blub paradox: if your language has a weak[1] type system, then it isn't capable of recognizing many problems as "type error". But stronger type systems can express stronger invariants. So something that isn't a type error in one language will be a type error in another. This changes how the programmer conceives of problems.
Example: missing a case in a switch statement isn't a "type error" in C or Java, but it is a "type error" in languages like Rust or ML, because they have sum types with exhaustiveness checking. Other examples: array bounds checks can be eliminated with dependent types; lifecycle bugs like use-after-free and double-free can be eliminated with substructural types.
[1] "weak" in an informal sense of "not very expressive"
I suspect a lot of people might have had bad experiences with codebases which overuse complex types or trying to type things like Redux which is messy. When I use TS for personal stuff I’ll typically be a bit loose about things like any in places where I don’t care (for now) and I feel it doesn’t add much overhead, but I have been using it for a long time so it’s become second nature.
"problems that are due to typing" is a very difficult thing to unpack because types can mean _so_ many things.
Static types are absolutely useless (and, really, a net negative) if you're not using them well.
Types don't help if you don't spend the time modeling with the type system. You can use the type system to your advantage to prevent invalid states from being represented _at all_.
As an example, consider a music player that keeps track of the current song and the current position in the song.
If you model this naively you might do something like: https://gist.github.com/shepherdjerred/d0f57c99bfd69cf9eada4...
In the example above you _are_ using types. It might not be obvious that some of these issues can be solved with stronger types, that is, you might say that "You rarely see problems that are due to typing".
Here's an example where the type system can give you a lot more safety: https://gist.github.com/shepherdjerred/0976bc9d86f0a19a75757...
You'll notice that this kind of safety is pretty limited. If you're going to write a music app, you'll probably need API calls, local storage, URL routes, etc.
TypeScript's typechecking ends at the "boundaries" of the type system, e.g. it cannot automatically typecheck your fetch or localStorage calls return the correct types. If you're casting, you're bypassing the type systems and making it worthless. Runtime type checking libraries like Zod [0] can take care of this for you and are able to typecheck at the boundaries of your app so that the type system can work _extremely_ well.
[0]: https://zod.dev/ note: I mentioned Zod because I like it. There are _many_ similar libraries.
Also, when you have types it changes how you code itself. When I change a schema or refactor some function, I don’t need to think at all to make sure I’ve updated all the code that depended on the old schema or API; just fire the TypeScript compiler and it tells me everything that needs to be updated.
I’ve also not seen any issues for a long while where I’ve missed some conditional case, because I use discriminated unions with switch statements more, something that looks weird in normal JS but is very useful with types, since it tells me if I missed a case automatically.
Add that I’m managing a team of engineers, and so I can easily make sure they’re also not missing cases either, by setting the convention and having them see the light.
Putting aside other things like for instance always knowing that we’ve validated inputs for API endpoints since unvalidated inputs are the unknown type and therefore effectively unusable; or always knowing we’ve parsed and serialized dates correctly since we use branded string types to distinguish them from any other string with 0 runtime impact; the list goes on.
So yeah, it might just be the case that you haven’t actually internalized what coding with types even means, so you’re unable to imagine how it can help you.
And nicely written TypeScript looks awesome, but badly written TypeScript can be a huge mess, as it can with any language, but TypeScript purists sometimes forget that the language is just a part of a nicely written and designed system.
Why not just appreciate the diversity of opinion and move on, rather than lecture people?
Some people feel more comfortable with JavaScript, Common Lisp, Lua, etc.
Some people feel more comfortable with TypeScript, Typed Racket, Luau, etc.
And that's okay.
Sometimes I just don't feel like dealing with those very few downsides though, but I can accept it's mostly personal preference.
At my age, sometimes I just don't want to deal with:
1. Yet another configuration file (tsconfig.json in this case). When something breaks, having one more place to look at is not something I want. The more extra files like this are needed for the development environment to even work (as in, something undesirable happens if you remove them), the less confidence I have in the project's long term reliability/stability.
2. That same configuration has misleading naming. The `"strict": true` setting should be called `"recommended": true`, or at least `"preset": "recommended"`, because it's not even strict. I would expect this `strict` flag to enable everything to the most restrictive way possible, and let devs disable checks (if) they don't want them. In its current state it doesn't enable strict checks like `noFallthroughCasesInSwitch`, `noImplicitOverride`, `noImplicitReturns`, `noUncheckedIndexedAccess`, `noUnusedLocals`, `noUnusedParameters` (I might be missing more).
3. Related to previous point: Inconsistencies between projects. So I work on one project with strict settings, tsc properly mentions possibly undefined accesses, etc; and then I move to a different project, and if I forget to context switch ("TypeScript config is different here"), I could be accidentally trusting the compiler to keep undefined accesses (and other stuff) in check, when it's not actually doing so.
4. Last time I checked, I couldn't just have a git repo "foolib" that is 100% TypeScript (100% .ts files, zero .js files), and `npm install` that repo on a separate project, and have it Just Work™. There's always extra steps that need to be done if you want to use .ts files from a separate package (usually compile to .js and install that; or using a bundler (read first point again)).
5. Why does the "!" operator even exist (or at least, why isn't there a flag to forbid it (for example the strict flag)). In my experience, using it is just developer laziness, where someone just doesn't want to write proper checks because "it's noise".
---
Those 5 points came off the top of my head so I'm almost certainly forgetting stuff.
It's mostly "death by a thousand cuts" kind of stuff, so sometimes I might not mind, but other times I might not be in the mood to deal with this and heavily influences my decision to go with TypeScript (keeping it approachable to as many people as possible) or a different language/ecosystem altogether.
Yes, I could "just" write a package that I can just npm install and it autoconfigures TypeScript and other stuff for me (and I have done so, for my own sanity). But I shouldn't need to do that, and it's too brittle for my taste.
This breaks my heart.
People who don’t like JavaScript but, for whatever reason, still want to write frontend apps have chosen to invent a new language that transpiles to it. To call that effort a standard is heartbreaking to me.
From the article it sounds like it was only used for the prototyping system so a single code base could run in the iOS client and the Web client.
I believe the main UI of Figma and what makes it so performant and magical to use is C++ https://www.figma.com/blog/webassembly-cut-figmas-load-time-...
Skew doesn't look fundamentally better enough that it would be worth the downsides. Lack of IDE support alone is probably enough to cancel out a productivity gains from a better language.
Some parts are nice, like the string literal typing "this" | "that". Other things are hacky, like "branded types", gross.
But then I think of my commercial codebase which is extremely well tested, regular old JS, and wonder if is worth the hassle.
As a user I don't care about DX if the resulting UX is bad.
Figma itself has no opinion about the resulting UX. It's a tool for designers, and they can design great UX, horrible UX, and everything in between.
Your question is kind of like saying "I want to see a house built with a hammer, to see if a hammer makes nice looking houses".
If Figma helps building lean designs it's good otherwise not.
Designers tend to put too much useless parts into sites, like unnecessary transparencies and animations.
The latter one is harder if you only have a knife instead of an assault rifle.
On mobile I have a limited data plan and the speed isn't always the best and on many pages I have to wait because beside the ads I have to download 3, 5, 10 or even more MB of data just to get pages where button, links and headline are undistinguishable because of recent design decisions.
Seems to me these tools are worthless in the end, if you are a user. After bootstrap it went pretty much downhill.
Not great at animations, not great at fully exploding all of the app state. Overall pretty good middle ground for designers and devs to interact.
Doesn’t even support more advanced prototyping things like inputs and dynamic changes.
Not a site builder
If you sign up for Figma, you can quickly get a sense of what it does. Some features are behind a paywall, but mostly things related to collaborating or managing large teams and design systems.
There are also approximately 1 billion Figma tutorial videos on Youtube that would show you the interface.