Overview of common new features for Typescript 3.8

Keywords: TypeScript ECMAScript less Attribute

Write on top

  • 3.8 added several interesting features, optimized the module part of ECMAScript, #use of private fields instead of less stringent privates, and so on.

1. Import and export methods for type restrictions (Type-Only Imports and Export)

TypeScript 3.8 adds a new syntax for type-only import and export.

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

export type { SomeThing };
Copy Code
  • You can try it on playground so that import and export will not resolve ts, this feature is not common, and you may encounter problems when your child configures
  • This functionality may be relevant if you encounter problems under the transpileModule API or Babel of --isolatedModulesTypeScript.

Extensions and other methods are not supported for new types of imports like this

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.

    // ...
}
Copy Code

2. Private fields for ECMAScript proposals (ECMAScript Private Fields)

2.1 Basic features of 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.
Copy Code

!!! Private fields have the following properties, unlike regular properties, which specifically compare the private modifier declarations here.

-Private fields begin with the `#'character.Sometimes we call these `prviate name`.- Each private field name is uniquely limited to the class it contains.- `TypeScript`Auxiliary modifiers, such as `public', `private', cannot be used on private fields.- Private fields are inaccessible even outside the JS user, and cannot even be detected outside the included classes!Sometimes we call this strict privacy.

2.2 Specifications for the use of Private Fields

In addition to saving your own private property, another benefit of private fields is the uniqueness we just mentioned.For example, regular attribute declarations are easy to override in subclasses.Private fields are protected.

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'
Copy Code

Accessing any other type of private field will result in TypeError!!

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));
Copy Code

2.3 Should we use #customized private fields or private modifiers?

When attributes are involved, the private modifier of TypeScript does not execute properly; it behaves exactly like a normal attribute, and there is no way to tell it that using the private modifier does not work properly.We call it soft privacy, and we can still access it in the form of ['foo'].Look at the code below:

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'
Copy Code

The benefit is, of course, to help you solve compatibility issues when using some api s, but this approach is less rigorous.

  • It is completely inaccessible to compare #private fields used below
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'.
Copy Code

The conclusion is that if you want to strictly protect the values of your private attributes, you can use `#'without worrying about naming conflicts when subclasses inherit.When we still use `private', we need to be aware of the problem of modifying the value of the definition of the private modifier.

3. Use of export * as ns syntax

When importing a module's as to redefine the module name, we can re-export it to a separate module name.

// menu.ts

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

Copy Code

// module.ts

import * as menu from "./menu.ts";
export { menu };
Copy Code

ps: ECMAScript 2020 has recently added this syntax as well!

4. Top level await use

  • Usually we use JavaScript and often introduce an async function to use await.
  • In JavaScript (and most other languages with similar functionality), await is only allowed within the async function body.However, for top await, we can use it at the top level of the module.
async function main() {
    const response = await fetch("...");
    const greeting = await response.text();
    console.log(greeting);
}

main()
    .catch(e => console.error(e))
Copy Code
  • Specific modules participate as follows:
const response = await fetch("...");
const greeting = await response.text();
console.log(greeting);

// Make sure we're a module
export {};
Copy Code

Note that there is a subtle point here: the top level await only works at the top level of the module, and only when TypeScript finds a truly available module is allowed, we can use an export {} to detect whether it is used under the module.

This method is not recommended in experiments. Wait for 3.9

Reference resources

Posted by fahad on Sun, 19 Apr 2020 03:13:25 -0700