Brian Lovin
/
Hacker News
Daily Digest email

Get the top HN stories in your inbox every day.

thefaux

This is incredibly impressive but I also simultaneously find it kind of depressing. In my not so humble opinion, typescript is already way too complicated and getting worse thanks to its velocity. A better approach would be to kill typescript's velocity by identifying a stable subset of the language that provides the vast majority of its benefits and optimize the heck out of a parser for that smaller language. This approach would be both easier and more sustainable since it would cap the language complexity making it easier to maintain and/or write alternative implementations.

thiht

That’s not my experience. If anything, I think the Typescript experience improves with each release: typings get more precise, the type system becomes more expressive and allows to simplify the type declarations that used to be more complex, and best of all, what worked before still works. And in most cases, you’re good to go with the basics, you just know that if you need to declare a complicated type, Typescript got your back.

esperent

I agree that Typescript improves with each release as I and the people I work closely with use it, because we use the KISS approach to typing so we rarely do use new features, but when we do need them they're useful.

But then I find some third party code which seems to use the kitchen sink approach to typing, AKA the "look at how smart we are" approach, and it's a nightmare to understand. A type system is supposed to make code easier to work with, by the time you're spending more time understanding the types than the actual code there's something wrong.

In these cases I wish Typescript was more limited and I would gladly give up a lot of the new stuff to enforce simple types across the ecosystem.

That said, I don't really have an opinion on who is at fault here - coders for writing overly elaborate types, or Typescript for allowing them.

goto11

> That said, I don't really have an opinion on who is at fault here - coders for writing overly elaborate types, or Typescript for allowing them.

Backwards compatibility is to blame. Typescript was designed to support a number of patterns which was already used in JavaScript.

For example events are registered in the DOM like `element.addEventListener("click", (ev) => ...)`. The type of the callback will depend on the string passed as the first argument, so the type system need to support literal strings as type discriminators which is a weird feature not necessary in most other languages. If the API had been designed with static typing in mind from the beginning, it would have been designed differently and wouldn't need such a complex type system.

Aeolun

> A type system is supposed to make code easier to work with, by the time you're spending more time understanding the types than the actual code there's something wrong

This may be true in a lot of cases, but certainly not all.

I’ve spent a ton of time on the types that validate that the input/output schema of my request handler function matches the defined schemas, and that was hell, but now any other of our developers will see delightfully red squiggles when they do something wrong. That’s a force multiplier and absolutely worth the effort.

citrons

Also agree, with each release I get an "Eureka effect" that now I can solve the type issue I strugled couple months ago trying to create to just make some highly used function safer/easier to use for the developers.

Example the new satisfies and some upcomign "as const" features to generics I'm looking forward to

solarkraft

What's bad about using clever types? My (limited) experience is that if they're done well they just work. I don't know why React-Query's types work the way they do, but I quite like that they do. Developing an intuition for it was a bit hard, but I believe this might rather be a failure of the documentation.

brundolf

TypeScript is complicated because JavaScript is complicated. As long it's sticking to the core goal of giving JavaScript static types in a practical way, complexity is unavoidable. I think what you want is a new language.

(I say this not as a dig against TypeScript or the way it's been designed; I just think the parent wants it to be something fundamentally different from what it is)

zem

as someone working on a python type checker I can second this. we get occasional complaints that some feature is too complicated or too liberal, and the answer is usually "it works this way because python works this way, we are trying to support as much valid python as we can even if it's hard to express in terms of static types".

hajile

People would benefit more from a stricter subset of JS that has decent performance characteristics and actually sound typing.

AA-BA-94-2A-56

I agree, but I can't help but think of that meme about there being N+1 standards. The introduction of a stricter subset of JS will make Javascript more complicated, not less. I hate that, because honestly Javascript and the web would benefit form removing a lot of the cruft.

scotty79

At this point any other language soundly typed or not is semantically a subset of JS (at most plus some of their weird thing, like Rust ownership and move semantics). You are free to pick one and let JS be JS in all its glory.

solarkraft

"use stricter"

Analemma_

Or more precisely, TypeScript is complicated because people insist on doing deranged things with JavaScript and its mess of a type system. TypeScript wouldn't need to contain so much complexity if the underlying JavaScript was doing simple, straightforward things. Blaming TypeScript here is kinda shooting the messenger.

brundolf

It doesn't try to protect you from the really deranged things. Every TS check comes with an implied "assuming you didn't use a Proxy to make this property accessor mutate state or something"

It does reach admirably far into checking the regular dynamic-language programming patterns like using string variables to index into structures. Which is where a lot of its complexity comes from, but I wouldn't call that stuff "deranged". JS is a dynamic programming language, and people write it like a dynamic programming language, and typescript decided to meet it where it was at, which is probably the only reason it's gotten so much traction in the first place

scotty79

You may not like this freedom, but I absolutely adore it. I really feel restricted when I'm writing in other languages, even dynamic ones after JS and TS shown me what should be possible.

wruza

The whole “Type manipulation” section has nothing to do with this issue, but at the same time is the usual source of complexity in type definitions. Even worse, it serves as a clever challenge for people to make such dynamic interfaces well-typed, instead of making it boring, autogenerated once and then discouraged.

ajkjk

Can't agree. Typescript already has a better type system than a lot of languages in common usage, but it's not good enough and we run into issues all the time because it's not powerful enough. It can probably stop adding features someday, but IMO that day is at least a few years away, when it is actually solving the problem of type safety in web development fully.

ajkjk

In particular, supporting nominal typing, fixing the way index types work, and fixing the story of debugging type failures on giant unions come to mind, but there are countless others. (Don't @ me, my day job is a few versions behind and I can't remember what's in the latest version, but there are plenty of other things if not these.)

svieira

FYI, TypeScript already supports nominal types, but the ways in which you "spell" `nominal` are a little unintuitive:

1. Use an enum

2. Use an intersection with an enum and literally anything else (except a number)

3. Use a private field (only works with classes)

4. Use a `declare const FOO: unique symbol` keyed object intersected with anything else (works with everything including numbers, lots of boilerplate to declare a new nominal type).

the_duke

My biggest wish would be proper sum types. The current way of manually creating tagged unions is really awkward.

But that won't be added because there is no native JavaScript equivalent.

culi

Yeah I think the new `satisfies` operator and improvements to type inferences in the latest version likely resolve a lot of your concerns.

TypeScript also supports some really advanced typing I've yet to see in other languages like template literal types (don't @ me, I mostly work with dynamic languages at my current job). I feel like even the TS docs haven't caught up to the full power of TS's full featureset

duped

It's also worse in a lot of ways, not due to problems with expressiveness but more soundness and specification. It's pretty easy to make TS keel over during typechecking.

The other issue with the typesystem is the (soon to be obviated) need to compile to decent javascript and interact with it. That made sense before WASM existed and it will make a lot less sense once the component model is stabilized.

otikik

Who is “we” in that phrase? It seems the people I know that use it (from the outside, I don’t do ux) seem content with the current state

ajkjk

Ah, 'we' as in me and the people I work with in my day job.

Waterluvian

The thing about TypeScript (or any language) is that one needs to recognize that many features aren’t for us normals. They’re for library developers doing all kinds of wild type stuff. I remember my eyes glazing over at the template literal typings and such. But someone on the discord was like, “if it seems overwhelming, you’re probably not the audience. But you’ll end up using it by using a library that leverages it.”

Always check ts-essentials for the ideal abstractions built with the wild new features.

smasher164

My favorite language in this category is MLscript. The best part is that type-checking it is decidable! https://github.com/hkust-taco/mlscript

ywei3410

Have you heard of ReScript [1]?

[1] https://rescript-lang.org/

MuffinFlavored

> typescript is already way too complicated and getting worse thanks to its velocity

Is it safe to say a non-zero portion of "the community" is headed the direction of:

write it in _____ + compile it to WASM + glue DOM stuff to it with some sort of JS bridge?

peatfreak

This sounds interesting to me, especially as somebody who was exactly zero interest in learning anything other than regular JS (i.e., no TypeScript, CoffeeScript, or any other JS-extension languages). Is this some kind of pattern, and do you know of any examples that show this?

giobox

I see a comment like this every time someone mentions WASM and have to eye-roll a little. Yes transpile-to-WASM techniques exist, but as someone like yourself with a self-professed inability to learn TypeScript, I don't think you are going to enjoy living on the edge of webdev with WASM either... The tooling is nowhere near as mature for one, which is always problematic when starting from a position of little knowledge.

Just search github.com and you will find countless example repos for many languages, but understanding typescript first is probably a more productive use of most people's time.

If you work in web-tech, I consider avoiding JS and TS to be almost negligent to some extent in 2022.

Zaskoda

I find this comment validating. Most of the languages I've used start to click and feel good after a while - but it feels like this just won't happen for me with typescript. I'm clearly missing some fundamentals and I'm not even sure what it is I need to go study.

soiler

Can you explain why you feel that way? I only know JS and TS, and I love TS. With both languages, I understand I'm missing out on a lot, but I kind of assumed that was normal with my level of study (that is, reading in depth to fix bugs or make new features, and generally no further).

evandwight

What doesn't click? I've found it pretty intuitive, though I've explicitly avoided making complicated types.

randomdata

The type erasure. You get this nicely expressive type system that can encode all sorts of useful metadata, and then you have to recreate it all again by hand in 'Javascript' to access it at runtime.

Say I have `type Foo = 'bar' | 'baz'` and want to validate that an input string is within the set of Foo. Why can't I just enumerate the type to determine the valid values at runtime?

Tade0

> But there's a problem. Rewriting a library like TypeScript is extremely challenging. First, "absence of [a] specification" for TypeScript's behaviour. Donny's had to infer TypeScript's behaviour mostly test cases alone.

IIRC the TypeScirpt leadership is of the position that the implementation is the specification, which is unfortunate, because it means that the bugs in the implementation are necessarily part of the specification as well.

miohtama

For the sake of being fair for other programming languages, what are the languages with proper specification? C, C++, JavaScript, others?

randomdata

Go is staunch about its specification. To the point that the Go team maintains two independent compiler implementations to ensure that "features"/bugs in one implementation doesn't end up defining the standard and to ensure that a compiler can be implemented from the spec.

recov

There's actually 3 now from google afaik

- gc

- gccgo

- gollvm [0]

[0] https://go.googlesource.com/gollvm/

tristan957

Is the other compiler you are referring to gcc-go?

Uvix

C# has a spec, although it's a few versions out-of-date. https://github.com/dotnet/csharpstandard/blob/draft-v7/stand...

munificent

Dart has a complete specification. It tends to lag somewhat behind the most recent features (which are documented in separate language proposals), but we keep it as current as we can.

Maintaining a language specification is a lot more work than people realize, and a job that few have the skills to do well.

wtetzner

Standard ML, Scheme, Common Lisp, Java.

xchkr1337

In my opinion the presence of undefined behavior in the C/C++ specification makes it no better than the "specification by implementation" approach

yencabulator

C/C++ "undefined behavior" means your program is wrong and not within the spec, not that different compiler implementations might differ. There is no scenario in which any code with UB is valid, regardless of what compiler implementation you use. That's very different. (And IMHO a horrible feature of the spec, but it's there for historical reasons.)

C/C++ spec does have some "implementation defined behavior", which is where you can't rely on what will happen unless you know what compiler you're targeting. They are explicitly listed out as such, and not that common.

spac

without a specification you can never tell with certainty if there's a bug

duped

I guess you have to define "specification" because there's a spectrum. A full book describing the formal syntax, semantics, type system, and standard library/built ins (and macros, preprocessing, compiler flags, what have you) is fairly rare because of how big it needs to be.

Partial specification like the grammar, the type system, etc are more common (particularly because they're so useful for writing one implementation, let alone multiple!).

G3rn0ti

Raku fka Perl 6.

Alifatisk

Ruby?

steveklabnik

If you're referring to the ISO spec, it's effectively completely irrelevant.

If you're talking about ruby/spec, a comprehensive test suite is really great, but is also not what most people think about when they think of a spec, though it also may count! You could even argue that such a thing is better than a traditional spec.

ape4

Maybe the first step should be writing down a spec of TypeScript.

progx

Boring! That is the problem, nobody want to do such boring things.

yencabulator

Nobody except Microsoft is able to write a spec for Typescript. Microsoft has already declared that the implementation is it, any spec a random person writes will just be ignored.

epolanski

It's not about boredom, it's simply an implementation derived language as are Haskell or PHP or Python.

Having a spec is really valuable only if you intend to target different environments, that's a non-goal for TS it simply transpiles, rather than compiles, into another programming language.

It's also bound to follow each new JS feature and change.

Kuinox

Specification are not immune to bugs.

rk06

But you can use them as evidence that tsc is not working as it "should". Then go ahead and fix tsc Or spec or both as needed.

Without the specs, there is no way to tell if tac is behaving as developers intended it

Kuinox

Code, called implementation here, is a specification written in a certain grammar that is executed.

You want 'evidence' tsc is not working as it should, by writting a duplicated less specifying specification that would sometimes conflict with the typescript one.

It make me remember the people that wanted to specify everything and generate implementation from it: that called a programming language.

gfxgirl

It's not doing what I expect. Oh? Change the spec

It's not doing what I expect. Oh? Change the code

How is that different from now?

kristiandupont

And such a spec can be

1) a reference implementation,

2) written in natural language, or

3) written as formal semantics

#1 is the same as the current situation. With #2, you might get a bit closer but natural language has many ambiguities and idiosyncrasies that can render it useless in various situations.

You can try to define formal semantics, but that is not only hard to create, it's also hard to translate into an implementation, adding significant overhead in both parts of the process. And there can still be bugs, and there can still be edge cases with undefined behavior.

remexre

But at least formal methods tools can be applied directly to the specification, to show properties like "well, if you carve out this subset of TypeScript, you have something you can safely eval()" or "you can never have type errors with this usage of this construct in this way."

brundolf

> "well, if you carve out this subset of TypeScript, you have something you can safely eval()" or "you can never have type errors with this usage of this construct in this way."

This kind of certainty is very at odds with TypeScript's design philosophy and the way it (necessarily) works. Because it's overlaid on JavaScript, and JavaScript is wildly dynamic (Proxies, prototype modification, etc), almost nothing is known with absolute certainty. To deal with that, TypeScript makes a lot of "optimistic" assumptions, but holds them lightly (i.e. its assumptions may cause type checks to pass when they shouldn't, but it's not going to lean on them for anything that could really blow up if they're wrong)

IMO it strikes a very good balance given the constraints - not criticizing the designers at all - but TypeScript has to be treated differently than other statically typed languages might be, because nearly everything it knows/says is just a "probably"

zokier

> But at least formal methods tools can be applied directly to the specification

What makes you think that? For example for C language it has been significant effort to translate the specification to something analyzable by tools

namuol

Neither are programs, tests, or type definitions, but these are generally still valuable things to have.

the_gipsy

That's one way to keep tight control.

brundolf

I've poked around in the TypeScript codebase just a little bit, and it's clear they've squeezed as much performance out of JS as they can (though really, you can tell that just by using the thing; it's impressively fast even though it's still "slow"). It's funny to see stuff like bit-flags in a JavaScript codebase

I am a little surprised nobody at Microsoft has started working on an official native compiler (or maybe they have, and we just don't know about it yet). It does feel like they've hit a ceiling

epolanski

One of the core goals of TS is that it has to run in browsers, a native compiler is just not a good goal and it is not in the roadmap.

I think WASM is still not a good fit for a typechecking server.

brundolf

I wasn't aware of that as a core goal. Do you have a reference where it's stated?

I also don't see why WASM wouldn't be a good fit for that

epolanski

The core metric for TypeScript's success was to be able to put an IDE in a browser able to run and compile TypeScript itself, which is what the TypeScript team did with the Monaco (and Visual Studio Code) editor in 2011.

pjmlp

It does exist, for other purposes though, and only targets a subset.

https://makecode.com/language

It compiles to native code via C++.

pjmlp

It does exist, for other purposes though, and only targets a subset.

https://makecode.com/language

It compiles to native code via C++.

mgomez

At the beginning of this year, kdy1 (Donny) said he'd be switching to Go after initially trying things out in Rust [1][2], I guess he decided to go through with Rust after all? Or is this something slightly different?

[1] https://kdy1.dev/posts/2022/1/tsc-go

[2] https://news.ycombinator.com/item?id=30074414

clarkdave

From the interview (it's way down the page):

> The most challenging thing is the absence of the specification. I had to infer everything just from test cases.

> The second thing is the velocity of tsc. It's way too fast, and I was unsure if I could follow it up. So I decided to use semi-automated translation and selected Golang.

> But it was too boring, and more importantly, my programming ability has improved enough to follow tsc only by myself.

rob74

Looks like he moved back to Rust sometime between January and October, at which point he also changed the name to stc: https://kdy1.dev/posts/2022/10/open-sourcing-stc

CPUTranslator

From the main post and other comments it seems like it was for personal reasons, rather than pragmatic ones. They said they didn’t know how fast the Go implementation would be, but felt better about the original Rust one (I’m assuming before this really became a problem).

I think the reasons they switched are pretty weak, but justified at the same time. Kdy1 looks like more of a Rust person (their GitHub has more active Rust repos than Go), so this should’ve been the choice from the beginning. Going with the comfortable choice over the “pragmatic” one is almost always the best option if you’re the only contributor (or plan to be for a while).

noahtallen

This reminds me a bit of Rome, which aims to re-implement most parts of a JS tool chain without requiring dozens of different, misaligned dependencies. They also happen to be writing it in Rust, though they haven’t finished the bundler portion yet.

I wonder if there’s an opportunity for collaboration here!

https://rome.tools/blog/2021/09/21/rome-will-be-rewritten-in...

muglug

If you're just porting the code to a new language, the process can be significantly faster than writing it from scratch.

But if you're also re-interpreting the code, which seems to be Donny's approach, you can get bogged down with the discrepancies. The more the two diverge, the harder it is to debug discrepancies and keep track of updates in the upstream code.

I'm also porting a static analysis tool from an interpreted language to Rust, but it's a fairly straightforward port and I've been able to stick to schedule pretty well.

tuyiown

There is also the scenario that tsc is really not that good, and the discrepancies are not a problem enough to avoid potential stc benefits. This can eventually phase out tsc in typescript altogether, the core typescript team making stc the official implementation. This is especially credible with rust having good support with wasm, keeping the js runtime compatibility of tsc.

cardanome

Would that be a wise career choice for the people currently working on tsc?

Sounds more like they should purposely break compatibility form time to time to prevent Donny from catching up.

rk06

Should people really make their professional decisions based on future career choice? I think not.

Besides, such malicious action can easily be counterproductive.

People can just stop using tsc and switch completely to Rust version. Then, it would effectively make any development on tsc useless.

zellyn

The obvious solution is for Microsoft to hire him and support the Rust version as a first-class typescript compiler, no?

namuol

Maybe as an experiment. If it means sacrificing velocity, I don’t think it would ultimately be “blessed” by MS.

Perhaps a better way MS could contribute is to define a formal specification for the type checker, which would make efforts like this a lot easier.

But these aren’t mutually exclusive.

xiphias2

If the compiler team already spends a significant time optimizing the compiler, the difference in velocity may be not that much.

Achieving 100% compatibility on public code bases and switching is a great strategy at this point.

epolanski

Two compilers would be mostly a source of issues and reduce TS velocity.

All of that for what, slightly faster compilations? TS server is already fast enough for me to develop giant ts codebases in codespaces on 2 vCPUS with 4 GB of ram.

thenoblesunfish

If there was ever a HN headline I'd suspect of being machine generated, this would be it :D

ducaale

Slightly related, there is TypeRunner[1] which aims to rewrite a subset of TypeScript in C++

[1] https://github.com/marcj/TypeRunner

galaxyLogic

From the article some reasons not to use TypeScript:

"... in VSCode, the red lines and warnings take a long time to update on large projects.

... absence of [a] specification" for TypeScript's behaviour. Donny's had to infer TypeScript's behaviour mostly test cases alone.

The pure size of TypeScript is daunting. It's had ten years to iterate, grow and add features. "

---

Therefore for practical reasons, I stick with plain JavaScript (on Node.js etc.) and use a small assertions library

  https://www.npmjs.com/package/ok6
Assertions are the ultimate "types", they can assert any property you can express in your programming language. The key is to be able to make them succinct so they don't obscure your main code.

Yes they don't give you compile-time type-checking, which would be useful indeed. But as hinted at the excerpts above, in practice compile-time type-checking can slow you down.

In most case all I need is a way to prove to myself that "if this function runs a set of tests-cases, then the assertions in it are truthful. And, if anybody calls this function with wrong types of arguments my assertions will tell me there is a problem.

Often enough of a good thing is enough. You don't need the most sophisticated language and type-system to create robust programs quickly.

lmm

> Yes they don't give you compile-time type-checking, which would be useful indeed. But as hinted at the excerpts above, in practice compile-time type-checking can slow you down.

This is backwards. Having your type system be unplanned and ad-hoc is what makes it slow and complex (thus TypeScript, which had to retrofit a type system onto JavaScript), and making types be arbitrary runtime code is the epitome of that. There are better points on the expressivity/constraint tradeoff, but you'll only ever reach them by designing them into your programming language up-front; you can't retrofit consistency.

ajkjk

I dunno, I love types as documentations of how things are supposed to be structured. But I also agree that assertions are great because they can express any condition in the language. I wonder sometimes if it's possible to have a type system that is "any possible assertion, as a type".

galaxyLogic

I think the main difference between assertions and static type-checking is that ... static checking can do its checks at compile time. That is a great feature for big projects.

But the benefit of assertions is they can express arbitrary requirements, not only about the type of each argument and result but also about intra-arguments relationships between arguments, and also between arguments and the result.

As an example I could say:

    ok (argA < argB);
    ...
    ok (result > argA - argB); 
It's a tradeoff: More expressivity, simplicity and speed of development vs. earlier detection of type-errors.

consilient

Yes, this is called refinement typing (which is a special case of dependent typing). Idris and Agda are probably the dependently typed languages that are closest to being usable for general purpose programming, but they've still got a ways to go.

zem

in theory no, because you run into the halting problem. but even in practical terms it would impede your ability to do static type analysis long before that point.

ajkjk

I don't really care about static type analysis, in a sense:

If I write an assertion `x is a number`, then fine, statically analyze that, that works today.

If I write a hard-to-compute assertion like `x is Prime` (or `x is a counterexample to the Riemann Hypothesis`), then I don't care if the compiler can statically figure it out. It can simply require all callers to test that before calling this function, they assert `x is Prime` directly -- no analysis required. This way my function can be sure it is only called with prime numbers, but nobody has to write any logic in a typechecker that can figure out whether that's true for arbitrary inputs.

satvikpendem

This is like throwing the baby out with the bath water (and is very similar to what I see with people lambasting Rust for its memory strictness and then using C, C++ or Go). I'd take a slightly slower language with static types than reverting to using a dynamically typed language, any day of the week.

lizen_one

Rust is a "new" language and many packages from other languages get reimplemented in it. This is similar to Julia. Unfortunately, I had the experience that many Julia packages are not of high quality, not maintained, or do not run any more on the newest version.

How is this in Rust?

kibwen

Like every package repository (or human endeavor in general) it follows Sturgeon's Law: 80% of everything is crap. That said, there's 100k crates on crates.io, and many of them are fantastic (well-supported, actively developed, documented, etc.). For a new user, understanding which are high-quality is a daunting task, and is expedited by just asking an experienced person for specific recommendations.

satvikpendem

Honestly if you're writing Rust, just stick with the top 100 downloaded packages, and you'll be fine. That's basically what I do, unless the tasks requires quite specialized work.

civopsec

Didn’t expect to see such harsh criticism of the Rust ecosystem by this user.

steveklabnik

Contrary to the memes, a lot of long running Rust users are happy to tell you about where Rust is deficient.

Fuzzy_Logic

Although I cannot comment on this specifically for Rust, what I would confidently say is that one of the best methods for finding the “best” dependencies in any language is to read lots of code. Find the popular and/or most useful projects written in the language on GitHub and see which dependencies that project uses and how they are used. At least in my career this method has served me well. For a given problem domain I was able to quickly identify the best/most popular packages to use by reading the code that was heavily used by others. Obviously the more you do this the easier it becomes.

lmm

Julia's engineering is notoriously low quality (perhaps because it's more popular for scientific code). Almost any other language has a higher bar for what level of best practices is normal, IME.

vardump

I don't know how it's in general, but the few Rust packages I checked seem to be of very high quality.

pjmlp

Just as information that seems to be missing from other comments, there is already a Microsoft compiler for TypeScript, which compiles to native code via C++, however it is only a subset and is targeted to IoT

https://makecode.com/language

Daily Digest email

Get the top HN stories in your inbox every day.