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

[grammar] Syntax considerations #197

Open kaleidawave opened 1 year ago

kaleidawave commented 1 year ago

As I am building a checker for JS, I thought it would be a good to chime in with my point of view on some syntax things.

Firstly I think it would be great to standardise type syntax as a standard. Parsers and other tools are in the wild-west about how to handle type syntax. The most used type syntax extension don't have a good specification and process for adding syntax, leading some tools to be in the dark with trying to supporting codebases using it.

Things that I think would benefit from type annotations being in the source

Things that I think are important to upheld/accept in this proposal


So while I would like to see an improvement on this front I have some concerns and questions with how this implemented

Reading the current document (as of 25/09/23), I think the concept of defined type annotations is a better that the original idea of tokens/comments. I would back that decision up with:

IMO 90% of the type annotations from TypeScript are perfect. Those being

The ones that are of slight concern are the modifiers under TypeOperatorType. I wonder whether these could be just done as generics e.g. readonly T could be ReadOnly<T>?

Interface declarations and type aliases are pretty much fine. Not sure about IndexSignature though (if that is what I think it is).

I don't think there is any way an experimental checker could benefit from having different syntax here. I don't think a more minimal and fixed set holds checkers back

So 👍 for type annotations (in function parameters, return and variables) and the two types of declarations.


The slight concern is for other places where type syntax can crop up (in TypeScript and others). Removing these would make this proposal simpler and adhere to non-bias. Some of these have too high of precedence and leak types outside of where they are usually found in declarations and variables. If they were included I think it would be difficult to document on things like MDN without favouring a implementation of checking or being difficult to explain.

Here is an inconclusive list of things I don't think should be included:

Might have missed some others here. But those I think are cases that shouldn't be included in this specification. I think simplifying would the make this more acceptable to pass.

That is recommendations for syntax. I may open another issue later about reflection, runtime checking and direction later.

egasimus commented 1 year ago

Yay, Ezno - an actual alternative implementation of TS checking!

Glad to have you on here.

FWIW, a piece of feedback on part your list:

import type is a hint for bundlers (right?). If this was an engine, would it meant that the import doesn't import anything? Bit confusing so might be better to not include?

My experience with this: I'm building on top of some TypeScript libraries where the authors have used import indiscriminately, for types and values.

Apparently, everyone else ever who has ever used those libraries was doing it through a bundler, which papers over the issue (and then some). But as I tried to compile them with tsc to ESM (to use them with import maps - lovely instant feedback!), the type identifiers still ended up in the imports alongside the value identifiers, while the exported types were obviously stripped. As a result, the libraries promptly broke at runtime, due to trying to import things that weren't there.

Since those libs were not tiny things, but hundreds of files, my only option was to write an AST codemod utility (using recast), which parsed all the source files, took account of all exports (and reexports), determined what's a type and what's a value, and split each import line into separate import and import type lines.

So that's one failure mode to take into account. Not importing anything would've been fine, but not discriminating between value and type imports ended up trying to import types at runtime.

Import assertions might make good "canonical" alternative to import type.

The ones that are of slight concern are the modifiers under TypeOperatorType. I wonder whether these could be just done as generics e.g. readonly T could be ReadOnly?

Agree about doing these as generics by default. Still, it's nice how TS allows these as prefixes to constructor arguments, and declares/assigns them automatically. Maybe out of scope for type checking, though.

azder commented 1 year ago

import type is a hint for bundlers (right?). If this was an engine, would it meant that the import doesn't import anything? Bit confusing so might be better to not include?

I was thinking about it as I wrote https://github.com/tc39/proposal-type-annotations/issues/176#issuecomment-1732690996

Let's say the first step is not adding new syntax, similar to how EcmaScript 5.1 just added tools before EcmaScript 6 came along and built on top of it.

In that other comment, I tried to see if we can leverage an existing syntax like

import ts4 from './local/interface/definitions/file.v4.d.ts' assert { checker:  ['TypeScript','4','d.ts']  };
import flw from './local/interface/definitions/file.fjs' assert { checker:  ['Flow','0.217.0']  };

but then got into thinking... what would those ts4 and flw be?

In that other comment I mentioned someone might use out-of-band workers to provide load and run time checks, but an object returned via the imports with assertions or a global object that would provide a plug-in mechanism for any type checker for you to bring is also feasable I suppose, or hope so, through something like TypeChecker.register() utility.

I mean that as much in favor of

not going to be one-to-one with the whole of TypeScript's syntax

as I'm trying to envision extensibility beyond TypeScript and Flow as to not have

in the future converge towards standards rather than diverging.

at least not standardize type syntax into EcmaScript, but standardize extensibility.

And it could be extensible enough that someone might

Yes, the above sounds like annotations. Overlap? Complement?

niyarlatotep commented 1 year ago

Sorry to interrupt, I'm not an expert but maybe we can simply add way to rigister any typechecker or transpiler like it implemented in node js (or simular) i mean --loader (transpiler loader). And just write js code with types, then in the beginning of "main" module import this checker or transpiler and it will typecheck and transpile code on the fly. It's not resolve typing "forks" problem but it may be can solve transpile stage problem may be it's enough for the first step. Sorry if this isn't the topic.

theScottyJam commented 1 year ago

@niyarlatotep - you're welcome to open a new issue on that topic. I know some TC39 delegates shared some similar concerns, with the idea of "do we really need this, or would it be better to just provide options for different environments to be able to run TypeScript and other type checkers directly?". I saw this concern brought up in their meeting notes, but haven't really seen it get discussed in the github issues yet.