博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
TypeScript 2.7 记录
阅读量:5826 次
发布时间:2019-06-18

本文共 5320 字,大约阅读时间需要 17 分钟。

TypeScript 2.7版本记录

针对ts 2.7版本的特性作专门的实例,希望能加深理解。

增加常量声明的属性的支持(Constant-named properties)

对于常量,有更加智能的提示

const Foo = "Foo";const Bar = "Bar";let x = { // 2.7版本之前,x的类型为{[x:string]:string|number},现在为 {[Foo]: number;[Bar]: string;}}    [Foo]: 100,    [Bar]: "hello",};let a = x[Foo]; // has type 'number'let b = x[Bar]; // has type 'string'复制代码

typescript 增加一种新的类型声明:unique symbols,是 symbols的子类型,仅可通过调用 Symbol()或 Symbol.for()或由明确的类型注释生成

ES6 引入的 Symbol 机制,Symbol是js的第七种数据类型,可以产生独一无二的值,可以用来保证每个属性的名字都是独一无二,从根本上防止属性名的冲突。结合ts,我们可以这样声明一个symbol,const Foo: unique symbol = Symbol()

unique symbol 类型必须由 const 关键字声明

// Error! 'Bar' isn't a constant.let Bar: unique symbol = Symbol();复制代码

引用赋值一个 unique symbol 类型的值时候使用 typeof 操作符

// let Baz = Foo // 这样的话 Baz 的类型为symbollet Baz: typeof Foo = Foo // 类型为unique symbol// 在class里面使用 `unique symbol` 定义类的静态属性(不能用在类属性) 时,// 需要使用 `readonly static` 关键字来声明class C {    static readonly StaticSymbol: unique symbol = Symbol();}复制代码

当Symbol + const时,值的类型自动判断为unique symbol

// let SERIALIZE = Symbol("serialize-method-key"); SERIALIZE 类型为symbolconst SERIALIZE = Symbol("serialize-method-key");  // SERIALIZE 类型为unique symbol复制代码

接口中的计算属性名称引用必须引用类型为文本类型或 "unique symbol"

interface Serializable {   // [("serialize-method-key")](obj: {}): string; //error   [SERIALIZE](obj: {}): string;}class JSONSerializableItem implements Serializable {   //  error 只能用引入的SERIALIZE来作属性的名称   // ["serialize-method-key"](obj: {}) {
// return JSON.stringify(obj); // } [SERIALIZE](obj: {}) { return JSON.stringify(obj); }}复制代码

另外,两个unique symbol类型的值不能互相比较(当然除非其中一个值的类型为用 typeof 另外一个值)

新编译选项,更严格的类属性检查( --strictPropertyInitialization)

TypeScript 2.7引入了一个新的控制严格性的标记 --strictPropertyInitialization

现在,如果开启 strictPropertyInitialization,我们必须要确保每个实例的属性都会初始值,可以在构造函数里或者属性定义时赋值。

class StrictClass {    foo: number;    bar = 'hello';    baz: boolean;     // error,Property 'baz' has no initializer and is not definitely assigned in the constructor    constructor() {        this.foo = 42;    }}复制代码

有两种情况下我们不可避免该error的产生:

  1. 该属性本来就可以是 undefined 。这种情况下添加类型undefined
  2. 属性被间接初始化了(例如构造函数中调用一个方法,更改了属性的值)。这种情况下我们可以使用 显式赋值断言 (修饰符号 !) 来帮助类型系统识别类型。后面具体介绍它,先看下代码中怎么使用:
class StrictClass {    // ...    baz!: boolean;    // ^    // 注意到这个!标志    // 代表着显式赋值断言修饰符}复制代码

显式赋值断言(Definite Assignment Assertions)

尽管我们尝试将类型系统做的更富表现力,但我们知道有时用户比TypeScript更加了解类型

跟上面提到的类属性例子差不多,我们无法在给一个值赋值前使用它,但如果我们已经确定它已经被赋值了,这个时候类型系统就需要我们人的介入

let x: number;initialize();console.log(x + x);//          ~   ~// Error! Variable 'x' is used before being assigned.function initialize() {    x = 10;}复制代码

添加 ! 修饰:let x!: number,则可以修复这个问题

我们也可以在表达式中使用!,类似 variable as string<string>variable :

let x: number;initialize();console.log(x! + x!); //okfunction initialize() {    x = 10;}复制代码

添加 --esModuleInterop 对ES模块和老式代码更好的互通

这一块中文官网花了挺长篇幅来讲这个内容,我也是实践过才明白讲的是什么,需要理解 __esModule 标记是做什么的、es6模块经过ts转换成commonjs是怎么的、 如何保持与老式代码( CommonJS/AMD/UMD)的互通性

先说一下 --esModuleInterop 的作用:

  1. 默认开启allowSyntheticDefaultImports(那是肯定的,我们需要它来实现默认导入的功能)
  2. 命名空间导入不允许被调用或者构造,需要改成默认导入
import * as express from "express";// error 正确的实现导入方式应该是下面这种import express from "express";express();复制代码

注意: 我们强烈建议开启esModuleInterop,不管在新代码或者是老代码上。但该模式下会可能对已有的代码产生破环,对已有的命名空间导入(import * as express from "express"; express();)改成默认导入(import express from "express"; express(); )

让我们更深入理解,在 --esModuleInterop 下,ts对 import * 和 import default两种导入方式用两个helpers __importStar and __importDefault做分别处理。

构建前的代码:

import * as foo from "foo";import b from "bar";const a = 'newM'export default a复制代码

构建后的代码:

"use strict";var __importStar = (this && this.__importStar) || function (mod) {    if (mod && mod.__esModule) return mod;    var result = {};    if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];    result["default"] = mod;    return result;}var __importDefault = (this && this.__importDefault) || function (mod) {    return (mod && mod.__esModule) ? mod : { "default": mod };}exports.__esModule = true;var foo = __importStar(require("foo"));var bar_1 = __importDefault(require("bar"));const a = 'newM';exports.default = a;复制代码

这样做的结果是,我们新的代码不管是通过ts,Babel或Webpack来构建,都能通过 __esModule 来判断是否为es模块,如果无__esModule,则创建含default的对象保存模块,这样就完成我们要的默认导入功能,同时保持对老的库的支持

固定长度元祖

[number, string, string]类型的值 不可赋值 [number, string] 类型的值了。

[number, string]类型等同于下面的 NumStrTuple声明:

interface NumStrTuple extends Array
{ 0: number; 1: string; length: 2; // using the numeric literal type '2'}复制代码

NumStrTuple 代表类型为固定长度为2,[0]为number类型,[1]为string 类型的数组

如果不希望固定宽度,只需要最小长度,可以这样:

interface MinimumNumStrTuple extends Array
{ 0: number; 1: string;}复制代码

更智能的对象字面量推断

// 现在能正常判断obj的类型了,而不是之前的 {}const obj = test ? { text: "hello" } : {};  // { text: string } | { text?: undefined }const s = obj.text;  // string | undefined// { a: number, b: number } |// { a: string, b?: undefined } |// { a?: undefined, b?: undefined }let obj2 = [{ a: 1, b: 2 }, { a: "abc" }, {}][0];declare function f
(...items: T[]): T; // { a: number, b: number } |// { a: string, b?: undefined } |// { a?: undefined, b?: undefined }let obj3 = f({ a: 1, b: 2 }, { a: "abc" }, {});复制代码

其它

in操作符细化和精确的 instanceof

in 操作符 和 instanceof 运算符 更好用了(就是那么简单)

--watch,--pretty 编译

--watch 会在重新编译后清空控制台 --pretty 更好地展示错误信息

看图:


完。参考:

转载于:https://juejin.im/post/5aff1132f265da0b776ff22d

你可能感兴趣的文章
写一个dos批处理文件-更新svn,删除以前的内容,复制新的内容过来,启动nginx,启动notepad++编辑一个文件...
查看>>
桌面文件自动整理脚本
查看>>
spring cloud 学习(一)初学SpringCloud
查看>>
Collections.shuffle()用法
查看>>
用户体验技术优化系列(一)
查看>>
canvas入门笔记
查看>>
js代码小优化
查看>>
使用frp工具实现内网的穿透以及配置多个ssh和web服务
查看>>
电子邮件 -- 图解TCP_IP_第5版
查看>>
python面向对象(反射)(四)
查看>>
字符串转数字
查看>>
sql server 2008 中的 server profiler 的简单使用
查看>>
当文档载入完成时调用一个函数
查看>>
2sql
查看>>
ubuntu pulseaudio
查看>>
[leetcode-415-Add Strings]
查看>>
检测Apache是否支持mod_rewrite 如何开启.htaccess
查看>>
poj 1442 -- Black Box
查看>>
HDU 6153 拓展KMP (2017CCPC)
查看>>
注释、计算和变量
查看>>