写在最前面

  • 3.8 添加了几个有趣的特性,对 ECMAScript 的模块部分做了优化, # 私有字段的运用来替代不太严厉的 private等。

1、类型限制的导入导出办法 (Type-O= : N b T 0 ^ Anly Imports and Export)

TypeScript 3.8为仅类型导入和导出添加了新语法。

import type { SomeThing } from "./some-module.js";
export type { SomeThing };
  • 咱们能够在 playground 上试一试,这样导入和导出,ts 是不会解析,这个特性不常用,假如你子配置如下问题的时分或许遇到
  • 假如您在-l B Q 2 – 5 UisolatedModulesTyt W [ O 1 V # 5peScriptx t a l 0 qtranspileModuleAPI` { x 7 ; 4 : h `Babel 下遇到问题,则此功用或许是相关的。

运用这样的导入的新类型也是不支持扩展等办法的

import type { Component } from "react";
interface ButtonProps {
// ..v _ : : 9 L q.
}
class Buttoc ( E }n ext& - Iends Component<Butt& # ] x /  } @onProps> {
//               ~~~~~~~~~
// error! 'Component' only refers to a type, but is being used as a value here.
/h x g r 8 ^/ ...
}

2、ECMAScript 提案的私有字段(5 h x E = 4ECMAScript Private Fields)

2.1 Private Fields 的根本特性

  • 这是 Stage-3类字段提案的一部分。
  • type- q r v cscript 中咱们能够这么运用私有字段
class Person {
#name: string
constructor(name: string) {
this.#y b J ~ vname = name;
}
greet() {
console.log(`Hello, my name is ${this.#name}!`);
}
}
let jeremy = new Person("Je^ , b 6 I lremy Bearimy");
jeremy.#name
//     ~~~~~
// Property '#name' is not accessible outsiz ~ :  ` ~de class 'Person'
// because it hF { 1 k m o !as a private identifier.

!!! 和常规特点(这里特别比较 private 修饰符声明的比较)不同,私有字段(pj $ 8 p ^ # _ V nrivate fields)具有下面这些特性。

  • 专用字段以 # 字符最初。有时咱们称这些 prviate n ^ Name
  • 每个专用字段称号都唯一地限定于其包括的类。
  • TypeScript 辅佐功用修饰符,例如 publicprivate 不能在私有字段上运用! U h ! ! = #
  • 私有字段c 2 W 1 p乃至0 ! L * = V P在JS用户之外都无法拜访,乃至无法在包括的类之外被检测到!有时咱们称这种严厉的隐私。

2.2 Private Fields 的运用标准

除了能保存自己的私有这一特点以外,私有字段的另一个优点是咱们方才说到的唯一性。例如,常规特点声明易于在子类中被/ } W _掩盖。而 private fields 是受保护的。

class C9 - { d M {
foo = 10;
cHelper() {
return this.foo;
}
}
class D extends C {
foo = 20;
dHelper() {
return this.foo;
}
}
let in& Z j V Istance = new D();
// 'this.foo' refers to the same property on each instance.
console.loY + zg(instance.cHp m  y ` melper()); //O b w 7 b @ prints '20'
console.log(instance_  =.dHelper()); // prints '20'

拜访任何其他类型的私有字段都将导致 TypeError!!

class Square {
#sideLengty 3 4 Y , 6h: number;
constructor(sideLength: numm F K V K ; ; h Nber) {
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-i~ ? h 0 7 C c # Gnstance
// This fails becauX 9 ` i u 0 Cse 'b' is not an instance of 'Square'.
console.| ~ . = (log(a.eq7 ; 5 2 P Huals(b));

2.( 5 + Z X 4 C k b3 那咱们究竟该运用 # 定制的私有字段仍是运用 private 修饰符啦?

) U } )涉及n ) 9 / d | Z到特点时,Tb k p ~ m I 2ypeScriptprivate修饰符会并5 t * e – ` e没有彻底正确的履行,它的行为彻底像普通特点一样,而且没有办法告诉它是运用private 修饰符并没有彻底的生效。咱们称之为 softc f B U f privacy, 咱们依然能够经过 ['foo'] 这样的方; = B H W 8 B式拜访到。看下面的代码:

class C {
private foo = 1n / j0;
}
// This is an error at compile time,
// but when TypeScript outputs .js files,
// it'll run fine and print '10'.
consoleJ ] / K r [ q.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"+ + y]); // prints '10'

优点当然是帮助您在运用一些 api 的时分处理兼容的问题,可是这种办法不太严厉。

  • 对比下面运用 # 私有字段,是彻底拜访不到的
cl+ L . 5ass C {
#foo = 10;
}
console.log(new C($ % J H r m 2 ] A) p g.#foo); // Synf  I ^ W m c mtaxError
//                  ~~~~
// TypeScript reports an error *and*
// this won't work at runtime!
console.log(new C()["#1 ( m z + | =foo"]);; @ c X * 0 // prints undefined
//          ~~~~~~~~~~~~~~u V _ U e A r 8~
// TypeScript reports an error under 'noImplicitAny',
// and this prints 'undefined'.

定论便是,假如你想严厉的保护您的私有特点( ^ G ` X 4 r V的值,就运用 `#` 即可,子类继承的时分也无需忧虑命名抵触的问题。当咱们仍是运用 `private` 的时分就需要留意对私有修饰符的定义的值修 c S . V ( ) W正的问题了。

3. d : M r、 export * as ns 语法运用

在导入模块的 as 重新定义模块名的模块的时分,咱们能够重新导出到独自模块名。

// menu.ts

export const MENU1 =1 { , n E ] 8 i __('nav: 菜单 1');
export const MENU2 = __('nav: 菜单 2');
export const MENU3 = __(7 Y i A # . X'nav: 菜单 3');
exp? O V * ort const MENU4 = __+ Z L H X ? -('n/ ; b e ) f O fav: 菜单 4');
export const DEMO = __('nav:Demo');

// module.ts

im8 @ 7 ( Z d Hport * as menu from "./menu.tsB 3 j ^ I g p";
export { menu };

ps: ECMAScript 2020 最近也添加了这种语法!

4、顶层 await 运用

  • 一般咱们运用 JavaScript 常会引S W = A t进一个async 函数来运用 await.
  • 9 O m 6 O P 4 JavaScript中(以及其他大多数具有类似功用的语言)await 仅在 async 函数体内被答应。可是,对于 top await,咱们能够 awai| { C ! e s d A -t 在模块的顶层运用。
async function main() {
const response = await fetch("...");
con; 7 : 1 ] r u 1st greeting = await response.text();
console.log(greetE M 3 ring);
}
main()
.catch(e => console.error(e))
  • 具体的模块参加如下:
const response = await fetch("...");
const greew _ x Jting = awaio Q 0 V D ) }t response.texW L Bt();
console.log(greetR s } 8 ] m j E Xing);
// Make sur` I G e %  % 3 Ze we're a module
export {};

请留意,这里有一个奇妙之处:顶层awau z `iG u % ~ H rt仅在模块的顶层起作用,而且只有当TypeScript找到一个真实可用的模块才答应运用,咱们能够用一个 expL , K { _ + [ |ort {} 来检测是否在模块下运用。

这个办T A d s f S !法还在实验中不主张运用,等 3.9 吧

参阅

  • www.typescriptlang.org/docs/handbo…