TypeScript 3.6 发布,微软脚本编程语言

Haxe
4.0 已经发布了,Haxe 是一门新兴的开源编程语言,是一种开源的编程语言。内容如下:

TypeScript 3.6 已经发布了,更新内容如下:

动态编程语言 Julia 迎来了 1.0 正式版本,你可以通过这里下载 Julia 1.0
正式版。

和其它面向对象编程语言一样,ES6 正式定义了 class 类以及 extend
继承语法糖,并且支持静态、派生、抽象、迭代、单例等,而且根据 ES6
的新特性衍生出很多有趣的用法。

新的函数类型语法

使用更严格的生成器(Stricter Generators)

TypeScript 3.6 引入了对迭代器和生成器函数(generator
functions)的更严格检查。在早期版本中,生成器的使用者无法区分一个值是来自 yield
操作或是从生成器返回。

www.9778.com 1

另外,生成器仅仅假设 yield 类型是任意的:

www.9778.com 2

以第一段代码为例,在 TypeScript 3.6 中,检查器会知道 curr.value
的正确类型应为 string,并在最后一个示例中纠正对 next()
的错误调用。这要归功于因在IteratorIteratorResult类型声明中进行的一些更改而引入部分新的类型参数,以及 TypeScript
用于代表称为Generator类型的生成器。

该版本中 Iterator 类型允许用户说明 yield 类型、返回的类型和 next
可以接受的类型。

www.9778.com 3

在此基础上,新类型 Generator 是一个 Iterator,它同时存在 return 和 throw
方法,并且是可迭代的。

www.9778.com 4

为了区分返回的值和生成的值,TypeScript 3.6 将 IteratorResult
类型转换为联合类型:

type IteratorResult<T, TReturn = any> = IteratorYieldResult<T> | IteratorReturnResult<TReturn>;

interface IteratorYieldResult<TYield> {
    done?: false;
    value: TYield;
}

interface IteratorReturnResult<TReturn> {
    done: true;
    value: TReturn;
}

简而言之,这意味着在直接处理迭代器时,将能够适当地缩小迭代器的值。

为了正确表示可以从调用 next( ) 传入生成器的类型,TypeScript 3.6
还可以推断生成器函数主体内的某些 yield 用途。

www.9778.com 5

如果你希望显式,还可以使用显式返回类型从 yield 表达式强制执行返回、yield
和计算的值的类型。如下,只能用布尔值调用 next( ),并且取决于 done
的值,value 要么是 string,要么是 number。

/**
 * - yields numbers
 * - returns strings
 * - can be passed in booleans
 */
function* counter(): Generator<number, string, boolean> {
    let i = 0;
    while (true) {
        if (yield i++) {
            break;
        }
    }
    return "done!";
}

var iter = counter();
var curr = iter.next()
while (!curr.done) {
    console.log(curr.value);
    curr = iter.next(curr.value === 5)
}
console.log(curr.value.toUpperCase());

// prints:
//
// 0
// 1
// 2
// 3
// 4
// 5
// DONE!

Julia
可以看作是一门集众家之所长的编程语言,在首次公开时开发团队就已明确其需求:

一、类的基本定义

引入了用于指定函数类型的新语法,现在已经明确地将参数类型与返回类型分离,并支持参数名称。

更精确的数组扩展

在默认情况下,TypeScript
使用一个更简单的发射,它只支持数组类型,并支持使用 –downlevelIteration
标志在其他类型上进行迭代。在此标志下,发出的代码更准确,但要大得多。但是,在某些边缘情况下,受支持的数组还是存在一些差异,如下:

[...Array(5)]

等效于以下数组:

[undefined, undefined, undefined, undefined, undefined]

但是,TypeScript 将原始代码转换为以下代码:

Array(5).slice();

这是不一样的,Array(5) 生成长度为 5 的数组,但没有属性:

www.9778.com 6

当 TypeScript 调用 Slice( )
时,它还会创建一个数组,其中包含尚未设置的索引。

3.6 版本引入了一个新的 __spreadArrays 助手,用于精确地模拟 ECMAScript
2015 中在 –downlevelIteration 之外中发生的情况。__SpreadArray 也可在
tslib 中使用。

我们想要一种拥有自由许可的开源语言,同时拥有 C 的速度和 Ruby
的灵活。我们想要一种同像性语言,有像 Lisp 这样真正的宏,也有像 Matlab
这样的浅显熟悉的数学符号。我们想要一门像 Python 一样可用于通用编程,像
R 一样易于统计,像 Perl 一样自然地用于字符串处理,像 Matlab
一样强大的线性代数,像 shell
一样擅长将程序粘合在一起的语言。它简单易学,却能让严苛的黑客为之倾心。我们希望它是交互式的,具备可编译性。

基本所有面向对象的语言都支持类的封装与继承,那什么是类?

(name:String, age:Int)->Bool

Improved UX Around Promises

Promise 是当前处理异步数据的最常见方法之一,不幸的是,使用Promise面向对象的
API
通常会让使用者感到困惑。因此针对Promise被错误处理的情况,TypeScript
3.6 引入了一些改进。

例如,在将其传递给另一个函数之前,Promise忘记.then()或者await内容通常是很常见的。TypeScript
的错误消息现在是专用的,并告知使用者他们可能应该考虑使用await关键字。

www.9778.com 7

另外还提供快速修复:

www.9778.com 8

开发团队表示,围绕这一语言,一个充满活力的社区已蓬勃发展起来,为实现同一目标,来自世界各地的开发者们不断地重塑并精炼 Julia 。超过 700
人对 Julia 做出了实质性贡献,还有更多的人数以千计的令人惊叹的
Julia 开源包。总之,我们构建了这样一种语言:

TypeScript 3.6 发布,微软脚本编程语言。类是面向对象程序设计的基础,包含数据封装、数据操作以及传递消息的函数。类的实例称为对象。

arrow function syntax

更好的 Unicode 支持标识符

当发射到 ES 2015或其他时,3.6 版本包含更好地支持标识符中的 Unicode
字符:

www.9778.com 9

  • 快速:Julia 为高性能而生。Julia 程序通过 LLVM
    为多个平台编译高效本地代码。

  • 通用:它使用多分派(multiple
    dispatch)作为范例,使得表达许多面向对象和函数式编程模式变得容易。标准库提供异步
    I / O 、进程控制、日志记录、性能分析、包管理器等。

  • 动态:Julia
    是动态编程语言,与脚本语言相似,并且对交互式使用有很好的支持。

  • 专业:它擅长于数值计算,其语法非常适合数学,支持多种数字数据类型,和开箱即用的并行性。Julia
    的多分派非常适合定义数字和数组类型的数据类型。

  • (可选)多样:Julia
    具有丰富的描述性数据类型,类型声明可用于阐明和巩固程序。

  • 可组合:Julia
    的包可以很好地协同工作。单位数量的矩阵,或货币和颜色的数据表列都可以组合工作 –
    并具有良好的性能。

ES5 之前通过函数来模拟类的实现如下:

此版本引入箭头函数语法。

在 SystemJS 中支持 import.meta

3.6 版本支持在将 module 目标设置为 system 时,将 import.meta 转换为
context.meta。

www.9778.com 10

www.9778.com 11

// 构造函数function Person { this.name = name;}// 原型上的方法Person.prototype.sayName = function(){ console.log;};// new 一个实例var friend = new Person;friend.sayName(); // Jennyconsole.log(friend instanceof Person); // trueconsole.log(friend instanceof Object); // true
(a, b) -> a + b

get and set Accessors Are Allowed in Ambient Contexts

在早期版本的 TypeScript 中,并不允许在环境上下文中 set 和 get
访问器,其基本原理是,就写入和读取这些属性而言,访问器与属性并没有区别;然而,由于
ECMAScript 的类字段提案可能与现有版本的 TypeScript
中的行为不同,则需要一种方法来沟通这种不同的行为,以便在子类中提供适当的错误。

因此 TypeScript 3.6 中,用户可以在环境上下文中编写 getter 和 setter。

www.9778.com 12

想要尝试 1.0 的用户,如果是从 Julia
0.6 或更早版本升级代码,建议先使用 0.7 过渡版。0.7
版本包括弃用警告,可以帮助指导你完成升级过程。等到你的代码不再出现警告,就可以直接升级至
1.0 而不会产生任何功能性更改。已注册的软件包也正在利用 0.7 的过渡期发布
1.0 兼容的更新。

总结来说,定义一个类的思路如下:

不再支持自定义属性访问器

环境类和函数可以合并

在以前版本中,在任何情况下合并类和函数都是有错的。此版本中,环境类和函数(带有
declare 修饰符的类/函数,或 .d.ts 文件中的类/函数)可以合并。如下内容:

www.9778.com 13

而不需要使用:

www.9778.com 14

它的一个优点是可以轻松地表达可调用的构造函数模式,同时允许名称空间与这些声明合并(因为
var 声明不能与名称空间合并)。

当然,Julia 1.0
中最重要的一个新特性是对语言 API 稳定性的承诺:你为 Julia 1.0
编写的代码将可以继续在 Julia 1.1、1.2
等版本中运行。语言是“完全成熟的”,核心语言开发者和社区都可以专注于基于这个坚实的基础去构建软件包、工具和新特性。

1.需要构造函数封装数据2.在原型上添加方法操作数据,3.通过New创建实例

将属性访问器类型更改为(set,get),并使用由前缀 get_ 或 set_
后跟属性名称组成的标准 getter/setter 名称:

APIs to Support –build and –incremental

TypeScript 3.6 增加了两组用于操作项目引用和增量式程序构建的 API。

对于 –incremental,用户可以使用 createIncrementalProgram 和
createIncrementalCompilerHost API。用户还可以使用新的 readBuilderProgram
函数从该 API 生成的 .tsbuildinfo
文件中重新补充旧的程序实例,该函数仅用于创建新程序(即不能修改返回的实例,它仅用于其他
Create*Program 函数中的oldProgram 参数)。

Julia 1.0
不仅仅涉及稳定性,还引入了一些新的、强大的和创新的语言功能。自 0.6
版本以来的一些新特性包括:

ES6
使用class关键字定义一个类,这个类有特殊的方法名[[Construct]]定义构造函数,在
new 创建实例时调用的就是[[Construct]],示例如下:

class Test {

  @:isVar var myvar(get, set) : String = "Something";

  static function main() {
    trace (new Test().get_myvar());
  }

  public function new() {}

  public function get_myvar() : String { return myvar; }
  public function set_myvar(s:String) : String { return myvar = s; }
}

New TypeScript Playground

此版本中,新的 TypeScript playground 支持许多新的选择,包括:

  • target 选项(允许用户从 ES5 切换到 ES3、es2015、esnext 等)
  • 所有标记(包括 strict)
  • 对普通 JavaScript 文件的支持(使用 allowJS 和 CheckJS)

当共享链接到 playground
示例时,这些选项也会持续存在,这样用户就可以更可靠地共享示例。

  • 全新的内置包管理器带来了巨大的性能改进,使包及其依赖项安装变得前所未有的简单。它还支持
    per-project 的包环境,并记录工作应用的确切状态,以便与他人共享 –
    以及你未来的项目。此外,还引入了对私有包和包存储库的无缝支持。你可以使用与开源软件包生态系统相同的工具来安装和管理私有软件包。

  • Julia 有一个新的缺失值表示规范。能够表示和处理缺失的数据是统计和数据科学的基础。采用典型的
    Julian
    方式,新的解决方案具有通用性、可组合性和高性能。任何泛型集合类型都可以通过允许元素包含预定义值来有效地支持缺失值 missing。在之前的
    Julia
    版本中,这种“统一类型化”集合的性能会太慢,但随着编译器的改进允许
    Julia 匹配其他系统中自定义 C 或 C ++
    缺失数据表示的速度,同时也更加通用和灵活。

  • www.9778.com,内置 String类型现在可以安全地保存任意数据。你的程序不会因为无效
    Unicode
    的单个丢失字节就浪费数小时或数天的时间。保留所有字符串数据,同时指示哪些字符有效或无效,使你的应用程序可以安全方便地处理具有所有不可避免的瑕疵的真实数据。

  • 广播(broadcasting)已经成为一种具有方便语法特性的核心语言功能 –
    它现在比以往更强大。在 Julia 1.0
    中,将广播扩展到自定义类型并在
    GPU
    和其他矢量化硬件上实现高效优化计算很简单,为将来更高的性能提升铺平了道路。

  • 命名元数组是一种新的语言特性,它使得通过名称有效和方便地表示和访问数据。例如,你可以将一行数据表示为 row = (name="Julia", version=v"1.0.0", releases=8)并使用 row.version访问该 version列,其性能与不那么方便的 row[2]相同。

  • 点运算符现在可以重载,允许类型使用 obj.property语法来获取除
     getting 和 setting 结构字段之外的含义。这对于使用 Python 和 Java
    等面向对象的语言进行更顺畅的互操作时特别有用。属性访问器重载还允许获取一列数据以匹配命名元组语法的语法:你可以编写 table.version访问 version列,就像使用 row.version访问 version行的字段一样。

  • Julia
    的优化器在很多方面远比下面列出来的还要更聪明,但这些亮点仍值得一提。优化器现在可以通过函数调用传播常量,从而允许比以前更好地消除无用代码和静态评估。编译器在避免在长期对象周围分配短期包装器方面也要好得多,这使得开发者可以使用方便的高级抽象而无需降低性能成本。

  • 现在始终使用与声明相同的语法调用参数类型构造函数,这消除了语言语法中比较模糊且令人困惑的角落。

  • 迭代协议已经完全重新设计,以便更容易实现多种迭代。

  • 作用域规则(scope
    rule)已经简化。无论命名的全局绑定是否已存在,局部作用域的结构现在都是一致的。这消除了先前存在的
    “soft/hard scope” 差异,并且意味着 Julia
    现在可以始终静态地确定变量是本地的还是全局的。

  • 语言本身非常精简,许多组件被拆分为“标准库”软件包,而不再属于“基础”语言的一部分。如果需要,可以导入它们(不需要安装),但它们不再被强加给你。在未来,这也将允许标准库独立于
    Julia 本身进行版本控制和升级,从而允许它们以更快的速度发展和改进。

  • 对 Julia 的所有 API
    进行彻底的评估,以提高一致性和可用性。许多模糊的遗留命名和低效的编程模式已被重命名或重构,以更优雅地匹配
    Julia
    的功能。这使得处理集合更加一致和连贯,以确保参数排序遵循整个语言的一致标准,并在适当的时候(更快的)将关键字参数整合到
    API 中。

/*ES6*/// 等价于 let Person = class {class Person { // 构造函数 constructor { this.name = name; } // 等价于Person.prototype.sayName sayName() { console.log; }}console.log; // functionconsole.log(typeof Person.prototype.sayName); // functionlet friend = new Person;friend.sayName(); // Jennyconsole.log(friend instanceof Person); // trueconsole.log(friend instanceof Object); // true

键值迭代器

Semicolon-Aware Code Edits

像 Visual Studio 和 Visual Studio Code
这样的编辑器可以自动应用快速修复、重构和其他转换,比如从其他模块自动导入值。这些转换由
TypeScript 驱动,老版本的 TypeScript
无条件地在每条语句的末尾添加分号;不幸的是,这不符合许多用户的样式指南,许多用户对编辑器插入分号不满意。

在此版本中,在应用这类编辑时,TypeScript
可以检测文件是否使用分号。如果你的文件是缺少分号,TypeScript
则不会添加分号。

此外,围绕 Julia 1.0 的新特性,还正在构建许多新的外部软件包。像是:

上面的例子中class定义的类与自定义的函数模拟类功能上貌似没什么不同,但本质上还有很大差异的:

for 循环语法现在使用新的语法支持在 键+值 对上的迭代:

Smarter Auto-Imports

JavaScript 有许多不同的模块语法或约定:ECMAScript 标准、Node
支持的模块语法或约定(CommonJS)、AMD、System.js
等等。在大多数情况下,TypeScript 将默认使用 ECMAScript
模块语法自动导入,在具有不同编译器设置的某些 TypeScript
项目中,或者在具有普通 JavaScript 和 Require 调用的 Node
项目中,这通常是不合适的。

在 3.6 版本中,在决定如何自动导入其他模块之前,它会查看现有的导入。

  • 改进数据处理和操作生态系统,以利用新的缺失支持。

  • Cassette.jl 提供了一种强大的机制,可以将代码转换传递注入
    Julia
    的编译器,从而实现事后分析和现有代码的扩展。除了用于分析和调试等开发工具之外,这甚至可以实现机器学习任务的自动区分。

  • 异构体系结构支持得到了极大的改进,并且与 Julia
    编译器的内部结构进一步分离。

函数声明可以被提升,但是class类声明与let类似,不能被提升;
类声明自动运行在严格模式下,“use strict”;
类中所有方法都是不可枚举的,enumerable 为 false。

for (key => value in collection) {}

Breaking Changes

类成员 constructor 现在是构造函数

根据 ECMAScript 规范,名为 constructor
的方法的类声明现在是构造函数,无论它们是使用标识符名称声明,还是使用字符串名称声明。

www.9778.com 15

www.9778.com 16

DOM 更新

在 lib.dom.d.ts 中已经删除或更改了许多声明,这包括(但不限于)以下内容:

  • 全局 window 不再定义为类型 Window,而是定义为类型 Window & type of
    globalThis。在某些情况下,将其类型称为 typeof window
  • GlobalFetch 移除了,而是使用 WindowOrWorkerGlobalScope
  • Navigator 上的某些非标准属性已经消失
  • experimental-webgl 移除了,而是使用 webgl 和 webgl2

JSDoc 注解不再合并

在 JavaScript 文件中,TypeScript 只会在紧接 JSDoc
注解之前确定声明的类型。

www.9778.com 17

关键字不能包含转义序列

以前,关键字被允许包含转义序列。3.6 版本不再允许:

www.9778.com 18

关于 TypeScript 3.6 更多信息,请见 TypeScript
网站。使用 npm 命令获取:

npm install -g typescript

还可以通过以下方式获得编辑器支持:

  • 下载 Visual Studio
    2019/2017
  • Visual Studio
    Code
  • Sublime Text 3 via
    PackageControl

发布说明:

(文/开源中国)    

有关更改的完整列表,可参阅:

二、更灵活的类

更多详情见发布说明:

  • 0.7 NEWS file

  • Julia 1.0

类和函数一样,是JavaScript的一等公民,并且注意到类与对象字面量还有更多相似之处,这些特点可以扩展出类更灵活的定义与使用。

(文/开源中国)    

2.1 拥有访问器属性

对象的属性有数据属性和访问属性,类中也可以通过get、set关键字定义访问器属性:

class Person { constructor { this.name = name; } get value () { return this.name + this.age } set value  { this.age = num }}let friend = new Person;// 调用的是 setterfriend.value = 18// 调用的是 getterconsole.log // Jenny18

2.2 可计算的成员名称

类似 ES6
对象字面量扩展的可计算属性名称,类也可以用[表达式]定义可计算成员名称,包括类中的方法和访问器属性:

let methodName = 'sayName'class Person { constructor { this.name = name; } [methodName + 'Default']() { console.log; } get [methodName]() { return this.name } set [methodName] { this.name = str }}let friend = new Person;// 方法friend.sayNameDefault(); // Jenny// 访问器属性friend.sayName = 'lee'console.log // lee

想进一步熟悉对象新特性可参考: 对象的新功能与解构赋值

2.3 定义默认迭代器

ES6
中常用的集合对象和字符串都是可迭代对象,如果类是用来表示值这些可迭代对象的,那么定义一个默认迭代器会更有用。

ES6 通过给Symbol.iterator属性添加生成器的方式,定义默认迭代器:

class Person { constructor { this.name = name; } *[Symbol.iterator]() { for (let item of this.name){ yield item } }}var abbrName = new Person(new Set(['j', 'j', 'e', 'e', 'n', 'y', 'y', 'y',]))for  { console.log; // j e n y}console.log // j e n y

定义默认迭代器后类的实例就可以使用for-of循环和展开运算符等迭代功能。

对以上迭代器内容感到困惑的可参考:迭代器与可迭代对象

2.4 作为参数的类

类作为”一等公民”可以当参数使用传入函数中,当然也可以从函数中返回:

function createClass { return new className}let person = createClassconsole.log // Person { name: 'Jenny' }console.log // object

2.5 创建单例

使用类语法创建单例的方式通过new立即调用类表达式:

let singleton = new class { constructor { this.name = name; }} console.log // Jenny

这里先创建匿名类表达式,然后 new
调用这个类表达式,并通过小括号立即执行,这种类语法创建的单例不会在作用域中暴露类的引用。

三、类的继承

回顾 ES6
之前如何实现继承?常用方式是通过原型链、构造函数以及组合继承等方式。

ES6
的类使用熟悉的extends关键字指定类继承的函数,并且可以通过surpe()方法访问父类的构造函数。

例如继承一个 Person 的类:

class Friend extends Person { constructor{ super this.phone = phone }}let myfriend = new Friendconsole.log // Friend { name: 'lee', phone: 2233 }

Friend 继承了 Person,术语上称 Person 为基类,Friend 为派生类。

需要注意的是,surpe()只能在派生类中使用,它负责初始化
this,所以派生类使用 this 之前一定要用surpe()。

3.1 继承内建对象

ES6 的类继承可以继承内建对象,继承后可以拥有基类的所有内建功能。例如:

class MyArray extends Array {}let arr = new MyArray, subarr = arr.sliceconsole.log // 4console.log(arr instanceof MyArray) // trueconsole.log // trueconsole.log(subarr instanceof MyArray) // true

注意到上例中,不仅 arr 是派生类 MyArray 的实例,subarr 也是派生类
MyArray 的实例,内建对象继承的实用之处是改变返回对象的类型。

浏览器引擎背后是通过[Symbol.species]属性实现这一行为,它被用于返回函数的静态访问器属性,内建对象定义了[Symbol.species]属性的有
Array、ArrayBuffer、Set、Map、Promise、RegExp、Typed arrays。

3.2 继承表达式的类

目前extends可以继承类和内建对象,但更强大的功能从表达式导出类!

这个表达式要求可以被解析为函数并具有[[Construct]]属性和原型,示例如下:

function Sup { this.value = val}Sup.prototype.getVal = function () { return 'hello' + this.value}class Derived extends Sup { constructor }}let der = new Derivedconsole.log // Derived { value: 'world' }console.log // helloworld

3.3 只能继承的抽象类

ES6
引入new.target元属性判断函数是否通过new关键字调用。类的构造函数也可以通过new.target确定类是如何被调用的。

可以通过new.target创建抽象类,例如:

class Abstract { constructor(){ if(new.target === Abstract) { throw new Error } }}class Instantiable extends Abstract { constructor }}// let abs = new Abstract() // Error: 抽象类 let abs = new Instantiable()console.log(abs instanceof Abstract) // true

虽然不能直接使用 Abstract 抽象类创建实例,但是可以作为基类派生其它类。

四、类的静态成员

ES6
使用static关键字声明静态成员或方法。在类的方法或访问器属性前都可以使用static,唯一的限制是不能用于构造函数。

静态成员的作用是某些类成员的私有化,及不可在实例中访问,必须要直接在类上访问。

class Person { constructor { this.name = name; } static create { return new Person; }}let beauty = Person.create;// beauty.create // TypeError

如果基类有静态成员,那这些静态成员在派生类也可以使用。

例如将上例的 Person 作为基类,派生出 Friend
类并使用基类的静态方法create:

class Friend extends Person { constructor }}var friend = Friend.createconsole.log(friend instanceof Person) // trueconsole.log(friend instanceof Friend) // false

可以看出派生类依然可以使用基类的静态方法。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。