TypeScript 3.1

元组和数组上的映射类型

TypeScript 3.1,在元组和数组上的映射对象类型现在会生成新的元组/数组,而非创建一个新的类型并且这个类型上具有如push()pop()length这样的成员。
例子:

type MapToPromise = { [K in keyof T]: Promise };

type Coordinate = [number, number]

type PromiseCoordinate = MapToPromise; // [Promise, Promise]

MapToPromise接收参数T,当它是个像Coordinate这样的元组时,只有数值型属性会被转换。
[number, number]具有两个数值型属性:01
针对这样的数组,MapToPromise会创建一个新的元组,01属性是原类型的一个Promise
因此PromiseCoordinate的类型为[Promise<number>, Promise<number>]

函数上的属性声明

TypeScript 3.1提供了在函数声明上定义属性的能力,还支持const声明的函数。只需要在函数直接给属性赋值就可以了。
这样我们就可以规范JavaScript代码,不必再借助于namespace
例子:

function readImage(path: string, callback: (err: any, image: Image) => void) {
    // ...
}

readImage.sync = (path: string) => {
    const contents = fs.readFileSync(path);
    return decodeImageSync(contents);
}

这里,readImage函数异步地读取一张图片。
此外,我们还在readImage上提供了一个便捷的函数readImage.sync

一般来说,使用ECMAScript导出是个更好的方式,但这个新功能支持此风格的代码能够在TypeScript里执行。
此外,这种属性声明的方式允许我们表达一些常见的模式,例如React函数组件(之前叫做SFC)里的defaultPropspropTpes

export const FooComponent = ({ name }) => (
    
Hello! I am {name}
); FooComponent.defaultProps = { name: "(anonymous)", };


[1] 更确切地说,是上面那种同态映射类型。

使用typesVersions选择版本

由社区的反馈还有我们的经验得知,利用最新的TypeScript功能的同时容纳旧版本的用户很困难。
TypeScript引入了叫做typesVersions的新特性来解决这种情况。

在TypeScript 3.1里使用Node模块解析时,TypeScript会读取package.json文件,找到它需要读取的文件,它首先会查看名字为typesVersions的字段。
一个带有typesVersions字段的package.json文件:

{
  "name": "package-name",
  "version": "1.0",
  "types": "./index.d.ts",
  "typesVersions": {
    ">=3.1": { "*": ["ts3.1/*"] }
  }
}

package.json告诉TypeScript去检查当前版本的TypeScript是否正在运行。
如果是3.1或以上的版本,它会找出你导入的包的路径,然后读取这个包里面的ts3.1文件夹里的内容。
这就是{ "": ["ts3.1/"] }的意义 – 如果你对路径映射熟悉,它们的工作方式类似。

因此在上例中,如果我们正在从"package-name"中导入,并且正在运行的TypeScript版本为3.1,我们会尝试从[...]/node_modules/package-name/ts3.1/index.d.ts开始解析。
如果是从package-name/foo导入,由会查找[...]/node_modules/package-name/ts3.1/foo.d.ts[...]/node_modules/package-name/ts3.1/foo/index.d.ts

那如果当前运行的TypeScript版本不是3.1呢?
如果typesVersions里没有能匹配上的版本,TypeScript将回退到查看types字段,因此TypeScript 3.0及之前的版本会重定向到[...]/node_modules/package-name/index.d.ts

匹配行为

TypeScript使用Node的semver ranges去决定编译器和语言版本。

多个字段

typesVersions支持多个字段,每个字段都指定了一个匹配范围。

{
  "name": "package-name",
  "version": "1.0",
  "types": "./index.d.ts",
  "typesVersions": {
    ">=3.2": { "*": ["ts3.2/*"] },
    ">=3.1": { "*": ["ts3.1/*"] }
  }
}

因为范围可能会重叠,因此指定的顺序是有意义的。
在上例中,尽管>=3.2>=3.1都匹配TypeScript 3.2及以上版本,反转它们的顺序将会有不同的结果,因此上例与下面的代码并不等同。

{
  "name": "package-name",
  "version": "1.0",
  "types": "./index.d.ts",
  "typesVersions": {
    // 注意,这样写不生效
    ">=3.1": { "*": ["ts3.1/*"] },
    ">=3.2": { "*": ["ts3.2/*"] }
  }
}

看完两件小事

如果你觉得这篇文章对你挺有启发,我想请你帮我两个小忙:

  1. 关注我们的 画漫画的程序员 GitHub仓库,让我们成为长期关系
  2. 把这篇文章分享给你的朋友 / 交流群,让更多的人看到,一起进步,一起成长!
  3. 关注公众号 「画漫画的程序员」,公众号后台回复「资源」 免费领取我精心整理的前端进阶资源教程

JS中文网是中国领先的新一代开发者社区和专业的技术媒体,一个帮助开发者成长的社区,目前已经覆盖和服务了超过 300 万开发者,你每天都可以在这里找到技术世界的头条内容。欢迎热爱技术的你一起加入交流与学习,JS中文网的使命是帮助开发者用代码改变世界