Open DonaldDuck313 opened 11 months ago
In short, it was decided against because it would mean that JS is responsible for defining and maintaining a type system. It looks simple enough with simple cases, like "x: string", but then you get into subclasses, generics, covariant and contravariant type variables, type functions, etc. It's a huge undertaking, much larger than just allowing the annotations themselves, and it would mean that the type system also ends up with the same back-compat constraints as the rest of JS, rather than allowing tools to experiment and upgrade over time.
I would like to strongly recommend that this discussion be reopened as the feature is completely non-viable without it.
Tell that to Python, which has a thriving ecosystem of type annotation tooling that is also completely meaningless at runtime.
@DonaldDuck313 I thought, there could be a switch similar to use strict 🤔
but then you get into subclasses, generics, covariant and contravariant type variables, type functions, etc. It's a huge undertaking
@tabatkins But these wouldn't have to be added right away, would they?
It looks simple enough with simple cases, like "x: string", but then you get into subclasses, generics, covariant and contravariant type variables, type functions, etc.
I agree, but you could just as easily be listing all the additional information you need to know before the basic syntax has the same meaning to the person who wrote it as it does to the person reading it.
This is not possible, because the person reading does not have any information about what type system the types were written for. If I say "I am going to eat this sandwich," but to me the word "sandwich" means "baseball", you might think upon hearing this that we have communicated successfully. You'd think that right up until you saw me eat the baseball (after all we are using the same syntax).
Of course this is all premised on the idea that the goal of language is to create communication.
Without creating communication the creation of language is impossible, and with the establishment of communication the creation of language is inevitable. Darmok and Jalad at Tanagra.
Yes, just like in Python (which has multiple typing tools that use similar, but not identical, syntax and behaviors, particularly for the complex stuff like what I listed), you have to know what typing tool the code is using in order to understand that code. This is not, in practice, an issue. (It's usually MyPy, occasionally PyType, checking the CI or the project metadata generally makes it obvious.)
@tabatkins Can you explain to me how you see this as bringing value to JS given that we already have type systems?
Another part of the reason I stand in opposition to this is that I sense that it is on some level a reaction to poor tooling design, which I do not feel is grounds for changing the language (but rather for changing the tools).
We do not have type systems in JS. We have separate languages that compile to JS which have type systems, but cannot be executed as JS. The parallel for Python would be if we had TypeSnake, which wasn't valid Python, but running MyPy would generate Python files from the TypeSnake and drop them into your project folder, where you could run them.
That much seems obvious to us both. Might I repeat the question? Given that we agree that derivate typed languages are not themselves JS, what is the benefit of this proposal to JS?
That is what the opening parts of the README for this repo cover: https://github.com/tc39/proposal-type-annotations?tab=readme-ov-file#motivation-unfork-javascript
One of the things that's kinda confusing about this proposal is that there are a ton of people who really love the proposal and can't believe we haven't shipped it yet, and a steady stream of people who write in to say that they think that it's completely pointless, baffled as to why anyone would want it at all.
I'm mostly convinced that this proposal has incommensurable value, unable to be discussed productively by people with different value systems.
But, sure, to answer your question: the goal of the project is to unfork JavaScript. But, you knew that already, right?
Many people filing issues on this proposal have argued that unforking JavaScript is pointless, having no benefit. And not just that it has no benefit, but that it obviously has no benefit.
And, dude, I just don't know what to tell you. You're in a minority point of view, as survey after survey shows, and I think most of us struggle to understand why you (and others) think that unforking JavaScript has no benefit.
Rather than shouting "what is the benefit?" I think you should look within. Why don't you want to unfork JavaScript? Is it because TypeScript and Flow have "poor tooling design"? That's a very unpopular position. People really love TypeScript, and would like JavaScript to grow closer to it.
People would like to ship TS or TS-like JS to npm, and have that "just work," without requiring downstream users to transpile, and without running into compatibility issues with different versions of TS (or different tsconfig
settings). Running TS as JS by just ignoring types gets you that.
But, you don't value any of that, I guess? So, what could we possibly say that would change what you value? Why do you suppose everyone else is wrong about what they want out of JS?
Again, I see NO benefits described in that section for JS or JS developers.
It claims the benefit will be "unforking" the ecosystem yet the JS ecosystem is not forked.
Thus this proposal effectively does the reverse of what it says on the tin: it takes an ecosystem (whole and undamaged) and forks it. Before this proposal, everyone who writes JS understands the words of the language to mean the same thing. Afterwards that will never be possible again.
To the extent that the ecosystem is forked it is the ecosystem of type checkers that is forked, but that neither falls under the purview of TC39 nor is it at all fixed by this proposal. It is not any comfort to me that everyone should use the same characters of syntax if they don't agree on what they mean.
Please cool it with the bold and the shouty caps.
I know how you feel; I've been in arguments like this before. Is the whole world insane except you?? And, I guess so, including me and everyone else in the surveys. But shouting at us isn't going to help.
To the extent that the ecosystem is forked it is the ecosystem of type checkers that is forked, but that neither falls under the purview of TC39 nor is it at all fixed by this proposal.
The TS owner is one of the champions of this proposal, because, if we can get this proposal over the finish line, TS will eventually stop being a separate language, and will instead be a linter of JS type annotations, like MyPy or PyType. TS and JS will merge and unfork.
I know, that's cold comfort to you, because you don't see any value in that. Even more surprisingly, you don't see why anyone values it. You don't really understand how anyone could disagree with you, or why bold/shouty caps doesn't help anyone.
I invite you to try harder to imagine why you're in the minority on all these surveys, and why other people think differently from you. (Hint: it's not really because only you perceive the truth and everyone else is just confused.)
Argumentum ad populum runs wild here. What an intellectual dwarf this dfabulich guy... on this disussion and many others, with such a consistency. Never giving actual counter arguments and always misrepresenting stuff to fit his narative. He knows that in fair discussion it will be made evident that the context proposal will worsen the ecosystem.
@dfabulich How would it stop being a separate language? I do not understand how this proposal would make Typescript any more or less of a separate language than it is right now.
To the extent that the ecosystem is forked it is the ecosystem of type checkers that is forked, but that neither falls under the purview of TC39 nor is it at all fixed by this proposal.
The ironic thing is, actual type checking is again outsourced outside TC39 to type checkers that can all have their own implementation. So, essentially, the problem is only moved somewhere else but not actually dealt with inside JavaScript itself.
Please be mindful of our Code of Conduct 🙏
@dfabulich if users want to simply[1] use typescript out of the box they should use bun or deno. this repo is a core ecmascript proposal and thus should be going its own path from first principles without necessarily worrying about the impact on prior art. the unforking comes after when prior art updates their code to use the new standard.
I am (and have been) working on a counterproposal which could solve the underlying problems. I am proposing a system of arbitrary syntax transformation -- a macro system for JS, if you will. I believe such a solution could have some benefits:
I am personally think that runtime type checking is impossible due to rich type system in TypeScript. For example take a look on type-fest library which has super complex utility types like this one. If there will be type checker in JS engine then it will have to evaluate and check everything.
Just take a look on how long it takes for TypeScript to check types in big projects and pretty much the same time browser will spend to do the same, of course it will be faster due to native environment, but still it will slow down page speed.
Another question is what to do if the types are incorrect (and maybe the code will work in runtime), should browser through an error and break the page, if not then what will be the point of real type checking?
I think maximum what is possible is some kind of type reflection, or adding the type text to decorators metadata to allow you to parse and use it in runtime (i.e. in schema validation like class-validator does)
I have read through the arguments about why adding runtime type checks is impossible, and I am forced to say that I concur with them.
Typescript already has a relatively advanced system which allows it to condition or refine its type understandings based on the results of runtime checks. That is already a powerful enough tool to be able to design an ideal system in which untrusted values are checked at the boundaries and internal static analysis can then be more or less "sound" in the type-theoretic sense. Because Typescript has such a system its system of type is able to have well-defined meaning, even in the absence of a compiler which emits any (non-explicit) runtime type checks.
It seems likely that similar mechanism would prove useful to many extenders, allowing them to marry their theory to Javascript's actual (runtime) type system, thus providing the means for consensus to be reached on which constructions are "correct" in their language.
I am personally think that runtime type checking is impossible due to rich type system in TypeScript.
Most of us have probably seen what kinds of monstrosities TypeScript is capable of committing when devs go wild and define acid trip like types, which extend themselves to infinity and beyond, resulting in more code for the types than for the actual code, it will result in JavaScript. No wonder why there are sometimes separate .d.ts
files. So, the rich type system can be as much an argument for inclusion into JavaScript as it can be on against it. Maybe, this kind of complexity isn't even needed in the first place, especially when it has no meaning in the language itself.
Given that we agree that derivate typed languages are not themselves JS, what is the benefit of this proposal to JS?
As I've said in my earlier comment referencing Python, it brings the same value to JS that Python's type annotations bring to Python.
Specifically:
(2 and 3, of course, apply to many possible solutions, including current TypeScript. 1 is the big difference from current practices. But it's important to keep 2 and 3 in mind, when weighing against proposals like runtime type checking.)
I apologize for apparently overexplaining earlier, but any assertion that this sort of system wouldn't be useful for JS needs to directly grapple with the usefulness of the same system in Python. If you have an argument against it, why does that argument not apply to Python's type annotations?
I too want a solution that hits points 1, 2, and 3!
As you mention the existing system hits points 2 and 3, but not 1.
This proposal satisfies 1 and 3, but not 2.
The difference with Python's system, now that I have a chance to sit down and look more carefully and look at Python's system, is that while Python allows multiple checkers it also defines the meaning of each of its typing syntaxes.
While a given checker is not specified, there is ample documentation in the base language on what the various typing syntaxes (like generics) mean and how you should write types for each kind of code. To me that is very different than how JS would be able to write the same docs, which is to say it wouldn't.
Since Python keeps getting mentioned, I think it's worth noting that, while Python doesn't assert type annotations at runtime (x: int = "one"
is OK), the type annotations are known at runtime.
from typing import get_type_hints
class Foo:
bar: str = "bar"
def __init__(self, baz: bool):
pass
get_type_hints(Foo) # {'bar': <class 'str'>}
get_type_hints(Foo.__init__) # {'baz': <class 'bool'>}
This allows users to use those type annotations at runtime. For example, to perform runtime type checking with the typeguard
library.
I think that forced runtime type checking has been discussed plenty, in this issue and others. But it might be worth discussing if types should really be completely ignored, or if they should/could somehow be available at runtime.
I am personally think that runtime type checking is impossible due to rich type system in TypeScript.
Most of us have probably seen what kinds of monstrosities TypeScript is capable of committing when devs go wild and define acid trip like types, which extend themselves to infinity and beyond, resulting in more code for the types than for the actual code, it will result in in JavaScript. No wonder why there are sometimes separate
.d.ts
files. So, the rich type system can be as much an argument for inclusion into JavaScript as it can be on against it. Maybe, this kind of complexity isn't even needed in the first place, especially when it has no meaning in the language itself.
real talk, half the time in Solidjs you are fighting types
According to the description of this proposal,
I think it would be better if type checking were done at runtime. To be clear, I suggest that the type checking should be done when running the actual code similar to what is done in PHP, not when parsing it similar to what is done in TypeScript. So for example I suggest that this:
should do roughly the same thing as this:
You mention in your FAQ that
While this is true for transpilation, if type checking isn't done at runtime as you suggest, the code will still have to be run through static type checkers. If type checking were done at runtime, however, it would allow to run the code directly in the browser in a type safe way without using any third-party tools to analyze it at all.
Is there any reason why you decided not to do this?