Closed msadeqhe closed 1 year ago
Simply this would mean everything after
:
will be ignored.
I think the real hard question that needs to be answered is when to stop ignoring. "Ignore after token X," regardless of what X is, can be too broad a statement.
For example:
function foo(): void {}
declare const WIDTH: number;
declare const HEIGHT: number;
function randomPoint(): { x: number, y: number } {
return { x: Math.random() * WIDTH, y: Math.random() * HEIGHT };
}
For foo
, it seems obvious, right? Ignore everything between :
and {
? But what should happen with randomPoint
?
You could make that unacceptable syntax and require only identifiers as the return type. E.g. randomPoint(): {}
is invalid, but randomPoint(): Point
would be valid.
But if that is valid, then you'd need to define syntax for types to recognize where the type ends and the function body begins. In this case, :
is expected to be followed by a type, {
is an acceptable token to start a type, etc. etc., }
ends the type, then {
starts the function body.
So I think it's going to be really hard to "just ignore after TOKEN," and you're going to have to define a more strict set of acceptable and unacceptable tokens that can make up a type annotation.
You're right.
The rule of when to stop ignoring should be as simple as possible. For example, "stop after the next brackets (e.g. <...>
, [...]
, (...)
or {...}
) or expressions (a combination of operators and operands e.g. A & B
) or identifier<...>
".
If a statement or declaration starts with :
, JavaScript should ignore the whole line, if it has an opening bracket (e.g. <
, [
, (
or {
) within itself, Javascript should ignore until it finds the corresponding closing bracket (e.g. >
, ]
, )
or }
) even if it is within multiple lines.
On the other hand, a complicated rule will affect Javascript interpreter performance.
For example:
function foo(): /*next expression*/ void /*stop*/ {}
//...
function randomPoint(): /*next brackets*/ { x: number, y: number } /*stop*/ {
return { x: Math.random() * Width, y: Math.random() * Height };
}
Within return
the :
is a part of object creation and will be not ignored. But :
within declarations are types as comments.
Another possible syntax for generics would be:
function foo:<T>(x: T) {
return x;
}
class Box:<T, U> {
value: T;
constructor(value: T) {
this.value = value;
}
}
:type Foo:<T> = T[]
:interface Bar:<T> {
x: T;
}
add:<number>(4, 5)
another:<number, number>(4, 5)
new Point:<bigint>(4n, 5n)
To differentiate between declarations and invocations, if it starts with function
, class
, :type
or :interface
, it would be a declaration, otherwise it's an invocation.
I like this idea, but not the :import
and :export
, normal ones can be used since types and interfaces is something you would like to export too.
Do you mean if we import and export the whole type as comments instead of :import
and :export
?
export :type SpecialBool = boolean;
export :interface Person {
name: string;
age: number;
}
import :type { Person } from "schema";
Do you mean if we import and export the whole type as comments instead of
:import
and:export
?
Yes, I find it nicer.
By the way, I think you are missing an equal sign, I think it should be export :interface Person = {
.
How do you handle some other odd-ball scenarios, like these?
// Do you really want to stop parsing the type after the first closing bracket?
// How would you handle these?
function fn(): { x: number } | { y: number} { ... }
function fn(): number[] | null { ... }
// And what about this? Is this a function who's return type is a readonly object of some sort,
// and it's missing a function body, so this should be a syntax error?
// Or is this a function who's return type is just "readonly", and we don't ignore those curly brackets?
function fn(): readonly { ... }
What about inline-operators, like as
, how would those get handled? If they are included, what rules should be used to know when the types stop.
return x as y | z // Is this a bitwise-or, or a union type?
You're right. It's not possible to make things simple with the current syntax. I hope TypeScript, Flow, and etc, could change their syntax to make Type as Comments as simple as possible. For example, if the syntax would be :{type}
:
function fn():{{ x: number } | { y: number}} { ... }
function fn():{number[] | null} { ... }
function fn():{readonly} { ... }
return x :{as y} | z
Can I think that this plan is like:
:
and later type-units ({...}
, [...]
, (...)
, <...>
and identifiers) as type syntax.:
is at the beginning of the line, the current line (type-units across multiple lines as a line) is taken as the type syntaxThe above content is the translated content, and the original text is as follows:
我是否可以认为这个方案是:
1. 将 `:` 及其后的类型单元(`{...}`,`[...]`,`(...)`,`<...>`, 标识符) 作为类型语法
2. 如果 `:` 在行首,将会把当前行整行(跨越多行的类型单元视作一行)作为类型语法
I close this issue, because issue #186 is a good alternative.
This is generalized from this issue. Everything related to types could be after
:
even for type declarations and interfaces. These are modified examples from README:Type Annotations
Type Declarations
Javascript would ignore statements which start with
:
:Classes as Type Declarations
Parameter Optionality
Optional parameters can have their own notation after
:
:BTW, Javascript already have
??
and?.
operators, thus allowing?:
within optional parameters seem natural and acceptable.Importing and Exporting Types
Javascript would ignore statements which start with
:
:Type Assertions
Javascript would ignore
:as (...)
after expressions:Generic Declarations
Javascript would ignore
<>
,<,>
,<,,>
and etc after removing:TYPE
within them:Generic Invocations
Javascript would ignore
<>
,<,>
,<,,>
and etc after removing:TYPE
within them:Simply this would mean everything after
:
will be ignored. Also empty<>
,<,>
,<,,>
and etc will be ignored after removing:TYPE
within them.IMO, the original proposal from README is OK. My suggestion is just an option to consider, if the original proposal doesn't seem to be accepted in Javascript.