tc39 / proposal-type-annotations

ECMAScript proposal for type syntax that is erased - Stage 1
https://tc39.es/proposal-type-annotations/
4.27k stars 47 forks source link

cutting back scope #217

Open nektro opened 7 months ago

nektro commented 7 months ago

I think a first iteration of this proposal should limit itself to only the values from typeof, arrays, and classes in function parameter / variable / class field definitions. maybe the ?: and !. syntax too. this would provide an a common base that's easy for engines and tools to adopt while still being enough to bring immediate benefit to developers.

the readme goes into great depth about prior art but I dont think we should worry about tying ourselves strictly to being source-compatible with TypeScript due to the reasons y'all already have listed wrt standardization and not breaking the web. even though they and others have done a great job paving the road.

I also agree with engines ignoring the types at runtime while making the types available to tooling being invaluable. and that putting the types in-source is much better than in-comments.

type declarations etc massively increase the scope and potential ambiguity in the syntax. I think it would be very beneficial to developers and the prospects of getting this landed if we started much smaller and added other features in future proposals.

great work getting this to stage 1 and I'd love to help out materially where I can to help this along :)

nektro commented 7 months ago
TypePrimitive:
  undefined
  object
  boolean
  number
  bigint
  string
  symbol
Type
  TypePrimitive
  TypePrimitive [ ]
TypeAnnotation:
  ?(opt) : Type
LexicalDeclaration:
  LetOrConst Identifier TypeAnnotation(opt) Initializer(opt)
nektro commented 7 months ago
FieldDefinition:
  ClassElementName TypeAnnotation(opt) Initializer(opt)
nektro commented 7 months ago

production OptionalAssertion would be quite similar to OptionalChain but with ?. swapped for !.

conartist6 commented 3 months ago

I'd be in favor of this proposal so long as the types are checked at runtime. It's the only way you can be sure what the correct "JS type" is for something, and thus it's the only way to give the real words meanings.

conartist6 commented 3 months ago

Otherwise what would stop me writing this:

const foo: string = 5;

Remember this wouldn't be a coercion or an error: just an outright lie, and one that you have no spec-based grounds to reject as invalid.

conartist6 commented 3 months ago

Without any specification-based grounds to push back on such type lies, it would not be possible to use these annotations as a source of factual information to build better tools.

nektro commented 3 months ago

Otherwise what would stop me writing this:

tooling would tell you its wrong. there's notes in the README that the engines noticed that in practice the annotations werent really necessary in practice to generate performant code

shaedrich commented 3 months ago

tooling would tell you its wrong

If tooling is used. Having types and using tools are two separate things. But that is a debate on principles (see #205) and this issue probably isn't the place for this, as smarter people than me have their reasons for not going down this road.

conartist6 commented 3 months ago

tooling would tell you its wrong.

The situation for the person who develops the code remains wholly unaffected by this proposal. They see the same types they always saw, and they are still the only person who can get tooling feedback on the validity of those types.

Once the code has been divorced from its tooling and shipped, there will be no more chance of interpreting the types correctly or extracting meaningful information from them. So the person shipping the code gains nothing, and the person running it loses value.

spenserblack commented 3 months ago

I've asked this a few times when runtime type checking is mentioned, but I'll ask it again: what happens with large and/or deeply nested types?

const sum = (numbers: number[]): number => // ...

Now I call this function with a hard-coded value, e.g. sum([1, 2, 3, /* ... */ Number.MAX_SAFE_INTEGER]). Will the runtime typechecker traverse the entire value just to ensure that every single property matches the type signature? This can be really expensive at runtime. I'm limiting myself to the simple types defined in this comment, but this can be way more expensive with complex types.

These simple examples might seem absurd, but this can become a real issue. For example, reading JSON from an API. Are you saying that the runtime typechecker would need to assert that all of the data matches the type to ensure the nth value isn't a "type lie", instead of just allowing the developer to "trust" that the type will be as expected (assuming no error response)? If I'm reading a large amount of data, and possibly multiple pages of that data, do I really want the runtime to implicitly type-check all of that data just because I added an annotation?


Once the code has been divorced from its tooling and shipped, there will be no more chance of interpreting the types correctly or extracting meaningful information from them. So the person shipping the code gains nothing, and the person running it loses value.

Even if the types aren't asserted at all, here's what one gains from annotation:

In fact, using TypeScript with Vue + Vite does not assert types for the dev server^1. In my personal experience, the improved type hints are what I benefit from during development, and I don't suffer from a lack of type assertion.

Remember this wouldn't be a coercion or an error: just an outright lie

Without any specification-based grounds to push back on such type lies, it would not be possible to use these annotations as a source of factual information

Can I lie with un-asserted type annotations? Sure. I can lie like this in Python as of 3.12:

# Python
def get_number() -> int:
    """
    Totally gets an int!
    """
    return "one"

I can also lie in some form or another in nearly any language:

// Go

// GetNumber safely gets a number, and will totally not panic.
func GetNumber() int {
    panic("Pranked! I lied to you.")
}
// Rust

/// Returns `true` if `n` is greater than zero
fn greater_than_zero(n: i32) -> bool {
    // Oops!
    n < 0
}

I can even make a "type lie" in TypeScript itself.

// TypeScript
const n: number = "one" as unknown as number;

Making sure that you're not "lying" falls under the realm of testing. A type annotation, like documentation and variable names, communicates the developer's intent. Testing asserts if they are "lying" or not. And if you do find type checking to be useful, it's better to do it once, at compile-time. Instead of forcing everyone running the code to spend additional computation time asserting the types at runtime, have the writer(s) assert types on their device(s) at compile-time.

mstoecklein commented 2 months ago

Runtime type checker is a good idea, but please not in a production environment. This is something that can be an option (i.e. checking a box in the devtools). In case it's enforced on all scripts I can already see the performance issues. It's really not the responsibility of the runtime environment.

jeswin commented 2 months ago

I think a first iteration of this proposal should limit itself to only the values from typeof, arrays, and classes in function parameter / variable / class field definitions. maybe the ?: and !. syntax too.

Then this would be useless in nearly all codebases I've seen. Flow and TS have been around for long enough and developers have clearly voted for the level of expressiveness they'd like to see. If you fall too short, there won't be enough adoption.

nektro commented 2 months ago

something "winning" means it marketed and timed itself in a way to get the network effect, not necessarily that its superior. adding Flow or TS to vanilla ecmascript essentially wholesale would be an awful idea for many many reasons

shaedrich commented 2 months ago

Then this would be useless in nearly all codebases I've seen.

The whole thing is useless without any additional tooling. Not to say, problematic in some aspects as others have already mentioned.