Proposal static type constraints features

# 喻恒春 (16 days ago)

Hello all,

Sorry, I submitted a issue on the tc39/proposals/issues/146. It seems to be a mistake.

This proposal adds static type constraints features to ECMAScript, based on the existing syntax, just use the features of void.

It is located in the variable initial value or declares the parameter default value or the first statement of the body of the function.

Very embarrassing, my English is not awesome, so.........

Example: not all, See proposal

function CustomName(x = void ['', Number, mod.BigNumber]) {
  // Declarative results type, and the default value is not available
  void String;
  // same as void [String]
  // This function must eventually return a string
  // ...

class CustomClass {
  // ...

class PureStructure {
  constructor() {
    void {
      name: !String, // must be a name
      age: !Number,  // must be age
      email: String  // default undefined

class ClassPrototype {
  constructor() {
    void {
      name: String,
      age: Number,
      email: String

class FunctionPrototype {
  constructor() {
    void [[

-- YU HengChun

# kdex (16 days ago)

x = void([Number, mod.BigNumber]) is already valid syntax in ECMAScript, and you can't change its semantics willy-nilly. How do you guarantee that those who have used void in their code in the past don't suddenly see unexpected type errors?

Also, can you make an example of how you could assign a default value to x and support your type constraints? The problem that I see is that void already evaluates its argument to undefined, which means that you would be forced to do something like

function CustomNumber(x = void([Number, mod.BigNumber]) || 42n) {
	// …

which is arguably awkward.

# YU HengChun (16 days ago)

我的英文水平太 low, 辅助机器翻译, 看双语版吧. O_O

To avoid misunderstanding caused by machine translation, I use bilingual.

is already valid syntax in ECMAScript, and you can't change its semantics willy-nilly

首先, 这个提案要求更改语义才能实现静态类型. 如果这是绝对不允许的, 那这个提案应该被拒绝.

First of all, This proposal requires changing the semantics to achieve static typing. If this is absolutely not allowed, then this proposal should be rejected.

How do you ….. errors?

过去可能有人这样用, 但是, 谁写代谁负责, 即便这个提案不被通过, 该发生的错误还是会发生.

Someone may have used it in the past, but whoever writer is responsible for it.

Even if this proposal is not passed, the mistake will still happen.

Also ….. constranints?


The default value is still the original standard.

类型约束是我的提案, 可以附加到默认值之前.

The type constraint is my proposal and can be appended to the default value.

其实他们是独立的两部分, 只是用运算符 '||' 把他们合法的连接起来. 或许 '|' 更好,

They are two separate parts, and they are legally connected using operator '||' for backward compatibility.

Maybe '|' is better.

which means … do something like?


This proposal just describes how to write static type constraints.

现实中由编译器负责把静态类型约束部分抽离出来, 不参与默认值运算.

In reality, the compiler is responsible for pulling out the static type constraint part, Does not participate in the default operation.

这个提案和 asm.js 的做法非常相似, 并且增大了使用范围.

This proposal is very similar to the asm.js approach and increases the scope of use.

不只是在初始化时标记内建类型, 更广泛的应用于所有定义的类型, 所有初始化和声明.

Not only is the built-in type flagged at initialization, it is more widely applied to all defined types, all initializations and declarations.

E.g: asm.js

function geometricMean(start, end) {
  start = start|0; // start has type int
  end = end|0;     // end has type int
  return +exp(+logSum(start, end) / +((end - start)|0));


import types from 'asm-types';
function geometricMean(start=void(!, end=void(! {
  return exp(logSum(start, end) / (end - start));

If the proposal passes, then:

geometricMean('0','1'); // Throws TypeError: ....
geometricMean(0); // Throws TypeError: 2 argument required, but only 1 present.
geometricMean(0,1,2); // Throws TypeError: 2 argument required, but 3 present.
geometricMean(0,1); // Ok ...
# YU HengChun (16 days ago)



For safety, it may be a good idea to use it with default values.

  isUndefined = void Number,
    // Static type constraint does not take effect
  isNumberUndefined = void(Number)||undefined;
    // Static type constraint take effect


I'm not sure if it is necessary to support multiple levels of nesting

class ConfigType {
  constructor() {
    void {
      version: Number,
      encodeNames: Boolean,
      lines: [String],
      filename: String,
      linker: undefined || {       // Need support?
        statics: { [String]: Number },
# Isiah Meadows (16 days ago)

How this this syntax more useful than one derived from TS/Flow, like x: Foo?

Isiah Meadows me at,

# YU HengChun (16 days ago)

ps: Accidentally, the email just sent was sent to isiah. This is a copy

TS/Flow is better about static type constraints.

If the syntax of TS/Flow can enter the proposal, I will not submit this proposal.

The only benefits of this grammar are:

Even if the proposal cannot be passed, it will still work, at least for the type description.

So, in reality, this proposal will still be used. Of course, additional tools are needed.

At least code is not to tranfrom, is standard, legal, and can run ECMAScript.

这个语法真的不比 TS/Flow 好啥. 如果类似 TS/Flow 的语法能进入讨论阶段, 我也不用提交这个提案了.

该提案唯一的优势是: 即时因为某种原因无法通过, 至少类型描述部分是有效的.

所以, 在现实中, 这个提案还是会被使用, 因为它是合法的代码. 当然, 如果要让静态类型约束生效, 还需额外的工具配合(也是不想写这个工具, 我才提交提案的啊).

无论如何, 代码是合法的, 可运行的标准 ECMAScript, 再也不用转换了.

# YU HengChun (16 days ago)

Consider the significance of this proposal from another perspective:

  1. It is a native ECMAScript
  2. It can be regarded as an enhanced version of asm.js
  3. It has always existed, but it has been neglected and has not been fully utilized.
  4. The cost is much lighter than adding a new grammar
  5. After the proposal is passed, it will seamlessly connect with WebAssembly


  1. 它是原生的 ECMAScript
  2. 这几乎就是 asm.js 的加强版啊
  3. 本来就一直存在, 只是被忽略了, 未被充分利用
  4. 成本上比添加新语法要轻量的多
  5. 这个提案被通过后将和 WebAssembly 无缝对接
# YU HengChun (16 days ago)
function CustomNumber(x = void(Number, mod.BigNumber) || 42) {
  // ...

which is arguably awkward.

Easy, change the word well.

function CustomNumber(x = typeof(Number, mod.BigNumber) && 42) {
  // ...

ps: BUG! symbol [] is incorrect

# Jordan Harband (15 days ago)

To clarify from above; it's almost certainly not going to be web compatible to change how void works in expressions, so if another alternative isn't viable, then it's kind of a nonstarter.

A separate question is, how would String cover strings across realms, considering that 'abc' instanceof String already returns false even in the same realm?

# YU HengChun (15 days ago)

A separate question is, how would String cover strings across realms, considering that 'abc' instanceof String already returns false even in the same realm?

There is no such way in the proposal.


The real purpose of the expression in void is not the operation. It is description for typing, the literal semantics. It is compatible with the old engine. Even if it is operated, it will not have side effects.

The new engine will extract the type description, and will not operate on it.

void 中的表达式不是用来计算的, 是为了描述类型, 只是为了兼容陈旧的引擎, 在陈旧的引擎中它也是合法的, 老引擎里面它会被计算, 但不会有副作用.

新引擎会提取其中的类型描述, 不会去运算它.

So, The correct way is:

function CustomString(x = void( Object instanceof String) || 'abc' ) {
  // ...

The form Object instanceof TYPE is for backward compatibility.

# Jordan Harband (15 days ago)

What about existing code that might use void in a way that's confused with your static type proposal? Suddenly it would start behaving differently.

# YU HengChun (15 days ago)

Strictly speaking, the behavior is different.

However, can you provide me with a real, conflicting example?

Or you give me an example, I write a version of the proposal, you can test whether it is really harmful.

If it is finally proved that the semantics are different, but it is indeed harmless, it is normal to add new semantics.

In fact ECMAScript has been enriching semantics.

严格意义上讲, 这个提案的确产生了不同的语义行为.

但是, 你能举一个真实的例子来说明这个提案会产生冲突么?

或者, 你给我一个例子, 我用提案的写法写一个版本, 你可以测试下是否真的有危害.

如果最终证明虽然语义不同, 但的确是无危害性的, 那么添加新的语义是很正常的.

事实上 ECMAScript 就是在不断的丰富语义啊.

# Jordan Harband (15 days ago)

function f(x = void String) { return typeof x !== 'string' || typeof x === 'undefined'; } assert(f(3)) is code that might stop working properly if void String changes from being undefined to literally anything else.

2018-06-03 22:01 GMT-07:00 YU HengChun <achun.shx at>:

# YU HengChun (15 days ago)

You mean this...

The original:

function f(x) {
  return typeof x !== 'string' || typeof x === 'undefined'; 

The proposal:

function f(x = void String) {
  void Boolean; // The complete code should be like this
  return typeof x !== 'string' || typeof x === 'undefined'; 

Thank you, you actually provided an example to prove that the proposal is conflict-free.

Test code is casually written, the results of these two versions will be consistent.

我得谢谢你的关注(真的, 这样才可以有更多的验证). 你刚好提供了一个例子证明我的提案是无冲突的. 随便写测试代码吧, 这两个版本的结果完全一致.

# Jordan Harband (15 days ago)

There's the separate issue that "void" in no way connotes types, so that word wouldn't likely be acceptable, because it has no relevant meaning.

# YU HengChun (15 days ago)

This is easy to solve, we change the word. But the code will be longer.

The original:

function f(x) {
  return typeof x !== 'string' || typeof x === 'undefined'; 

The proposal: typeof version

function f(x = typeof(String) && undefined ) { // Attention can not be omitted: && undefined
  void typeof(Boolean); // or only: typeof(Boolean);
  return typeof x !== 'string' || typeof x === 'undefined'; 

这很容易解决, 换个单词就行. 但是代码会更长.

# Jordan Harband (15 days ago)

So now for every type annotation, someone has to add && undefined? That seems like a lot of confusing boilerplate to have to add.

# YU HengChun (15 days ago)

The typeof version does have this problem.

So, how to choose?

Maintain the original semantics of the word?

Or define new semantics for void?

# YU HengChun (15 days ago)

Or enable both versions at the same time?

# Jordan Harband (15 days ago)

The default alternative is "neither" - I think something as fundamental as type annotations would need to have intuitive and conflict-free syntax, and absolutely would have a way to work cross-realm with both objects and primitives, to both distinguish between them and to allow both (in the case of primitives other than null/undefined).

# YU HengChun (15 days ago)

I also want to see a better way.