【譯】Typescript 3.8 經常使用新特性一覽

寫在最前面

  • 3.8 添加了幾個有趣的特性,對 ECMAScript 的模塊部分作了優化, # 私有字段的使用來替代不太嚴格的 private等。

一、類型限制的導入導出方法 (Type-Only Imports and Export)

TypeScript 3.8爲僅類型導入和導出添加了新語法。html

import type { SomeThing } from "./some-module.js";

export type { SomeThing };
複製代碼
  • 你們能夠在 playground 上試一試,這樣導入和導出,ts 是不會解析,這個特性不經常使用,若是你子配置以下問題的時候可能遇到
  • 若是您在--isolatedModulesTypeScripttranspileModuleAPIBabel 下遇到問題,則此功能多是相關的。

使用這樣的導入的新類型也是不支持擴展等方法的react

import type { Component } from "react";

interface ButtonProps {
    // ...
}

class Button extends Component<ButtonProps> {
    // ~~~~~~~~~
    // error! 'Component' only refers to a type, but is being used as a value here.

    // ...
}
複製代碼

二、ECMAScript 提案的私有字段(ECMAScript Private Fields)

2.1 Private Fields 的基本特性

class Person {
    #name: string

    constructor(name: string) {
        this.#name = name;
    }

    greet() {
        console.log(`Hello, my name is ${this.#name}!`);
    }
}

let jeremy = new Person("Jeremy Bearimy");

jeremy.#name
// ~~~~~
// Property '#name' is not accessible outside class 'Person'
// because it has a private identifier.
複製代碼

!!! 和常規屬性(這裏特別比較 private 修飾符聲明的比較)不一樣,私有字段(private fields)擁有下面這些特性。git

  • 專用字段以 # 字符開頭。有時咱們稱這些 prviate name
  • 每一個專用字段名稱都惟一地限定於其包含的類。
  • TypeScript 輔助功能修飾符,例如 publicprivate 不能在私有字段上使用。
  • 私有字段甚至在JS用戶以外都沒法訪問,甚至沒法在包含的類以外被檢測到!有時咱們稱這種嚴格的隱私。

2.2 Private Fields 的使用規範

除了能保存本身的私有這一屬性之外,私有字段的另外一個好處是咱們剛纔提到的惟一性。例如,常規屬性聲明易於在子類中被覆蓋。而 private fields 是受保護的。github

class C {
    foo = 10;

    cHelper() {
        return this.foo;
    }
}

class D extends C {
    foo = 20;

    dHelper() {
        return this.foo;
    }
}

let instance = new D();
// 'this.foo' refers to the same property on each instance.
console.log(instance.cHelper()); // prints '20'
console.log(instance.dHelper()); // prints '20'
複製代碼

訪問任何其餘類型的私有字段都將致使 TypeError!!typescript

class Square {
    #sideLength: number;

    constructor(sideLength: number) {
        this.#sideLength = sideLength;
    }

    equals(other: any) {
        return this.#sideLength === other.#sideLength;
    }
}

const a = new Square(100);
const b = { sideLength: 100 };

// Boom!
// TypeError: attempted to get private field on non-instance
// This fails because 'b' is not an instance of 'Square'.
console.log(a.equals(b));
複製代碼

2.3 那咱們到底該使用 # 定製的私有字段仍是使用 private 修飾符啦?

當涉及到屬性時,TypeScriptprivate修飾符會並無徹底正確的執行,它的行爲徹底像普通屬性同樣,而且沒有辦法告訴它是使用private 修飾符並無徹底的生效。咱們稱之爲 soft privacy, 咱們依然能夠經過 ['foo'] 這樣的形式訪問到。看下面的代碼:api

class C {
    private foo = 10;
}

// This is an error at compile time,
// but when TypeScript outputs .js files,
// it'll run fine and print '10'.
console.log(new C().foo);    // prints '10'
// ~~~
// error! Property 'foo' is private and only accessible within class 'C'.

// TypeScript allows this at compile-time
// as a "work-around" to avoid the error.
console.log(new C()["foo"]); // prints '10'
複製代碼

好處固然是幫助您在使用一些 api 的時候解決兼容的問題,可是這種方法不太嚴格。async

  • 對比下面使用 # 私有字段,是徹底訪問不到的
class C {
    #foo = 10;
}

console.log(new C().#foo); // SyntaxError
// ~~~~
// TypeScript reports an error *and*
// this won't work at runtime!

console.log(new C()["#foo"]); // prints undefined
// ~~~~~~~~~~~~~~~
// TypeScript reports an error under 'noImplicitAny',
// and this prints 'undefined'.
複製代碼

結論就是,若是你想嚴格的保護您的私有屬性的值,就使用 `#` 便可,子類繼承的時候也無需擔憂命名衝突的問題。當咱們仍是使用 `private` 的時候就須要注意對私有修飾符的定義的值修改的問題了。 ide

三、 export * as ns 語法使用

typescript 也支持這種用法啦,在導入模塊的 as 從新定義模塊名的模塊的時候,咱們能夠從新導出到單獨模塊名。函數

// menu.tsfetch

export const MENU1 = __('nav: 菜單 1');
export const MENU2 = __('nav: 菜單 2');
export const MENU3 = __('nav: 菜單 3');
export const MENU4 = __('nav: 菜單 4');
export const DEMO = __('nav:Demo');

複製代碼

// module.ts

import * as menu from "./menu.ts";
console.log(menu.MENU1) // 'nav: 菜單 1';
console.log(menu.MENU2) // 'nav: 菜單 2';
// ....

export { menu };
複製代碼

ps: ECMAScript 2020 最近也添加了這種語法!

3.1 疑問?

import * as React from 'react'; vs import React from 'react'; 這兩個使用有什麼區別嗎?

import * as React from 'react';
...or like this:

import React from 'react';
複製代碼

The first imports everything in the react module (see: Import an entire module's contents)

The second imports only the default module export (see: Importing defaults)

簡而言之就是咱們使用的 import React from 'react' 實際上是導出的默認的模塊,而用到 * as 是導出所有模塊。

四、頂層 await 使用

  • 一般咱們使用 JavaScript 常會引入一個async 函數來使用 await.
  • JavaScript中(以及其餘大多數具備相似功能的語言)await 僅在 async 函數體內被容許。可是,對於 top await,咱們能夠 await 在模塊的頂層使用。
async function main() {
    const response = await fetch("...");
    const greeting = await response.text();
    console.log(greeting);
}

main()
    .catch(e => console.error(e))
複製代碼
  • 具體的模塊參加以下:
const response = await fetch("...");
const greeting = await response.text();
console.log(greeting);

// Make sure we're a module
export {};
複製代碼

請注意,這裏有一個微妙之處:頂層await僅在模塊的頂層起做用,而且只有當TypeScript找到一個真正可用的模塊才容許使用,咱們能夠用一個 export {} 來檢測是否在模塊下使用。

這個方法還在實驗中不建議使用,等 3.9 吧

參考

相關文章
相關標籤/搜索