, December 05, 2021

0 kết quả được tìm thấy

Có gì mới trong phiên bản TypeScript 4.5?

  • Đăng bởi  Groot
  •  Nov 23, 2021

  •   8 min reads
Có gì mới trong phiên bản TypeScript 4.5?

Phiên bản TypeScript 4.5 được phát hành vào ngày 17 tháng 11. Cũng khá lâu rồi TypeScript mới phát hành bản cập nhập tiếp theo. Vậy thì trong lần trở lại lần này sẽ có những cải tiến gì thú vị? Cùng đọc tiếp bài viết dưới đây nhé!

The Awaited Type

Trước bản phát hành này để nhận được return type của Promise, bạn sẽ phải sử dụng hàm infer . Ví dụ:

type Unwrap<T> = T extends PromiseLike<infer U> ? U : T;

const resultPromise = Promise.resolve(true);
// ✅ resultUnwrapType is boolean 
type resultUnwrapType = Unwrap<typeof resultPromise>;

Trong bản phát hành này có thêm một type mới đó là Awaited . Bạn không cần một custom mapped type giống như Unwarp trong đoạn code trên. Chúng ta đơn giản chỉ cần làm như sau:

type resultUnwrapType = Awaited<typeof reAvailable only under nightly releasessultPromise>;

Điều này mang lại những lợi ích sau:

  • Recursive unwrap
  • Không phụ thuộc vào PromiseLike để code của bạn "mạnh" hơn
  • Thêm overloads vào Promise.all, Promise.race, Promise.allSettled, và Promise.any để tận dụng Awaited<T>

Hãy xem một số ví dụ sử dụng khác nhau:

// ✅ type is string
type basic = Awaited<Promise<string>>;

// ✅ type is string
type recursive = Awaited<Promise<Promise<string>>>;

// ✅ type is boolean
type nonThenObj = Awaited<boolean>;

// ✅ type is string | Date
type unions = Awaited<Date | Promise<Promise<string>>>;

type FakePromise = { then: () => string };
// ✅ type is never
type fake = Awaited<FakePromise>;

Vô hiệu hóa Import Elision

Tại compile-tile TypeScript phát hiện xem module có được sử dụng trong emitted Javascript hay không. Trong trường hợp module không được sử dụng hoặc được sử dụng như là chú thích type, thì module đó không được nhập trong emitted code. Sự tách rời này giúp tối ưu hóa hiệu năng tốt hơn.

Bình thường thì điều này sẽ không ảnh hưởng gì đến tất cả các hoạt động còn lại. Tuy nhiên, có một số trường hợp tính năng này có thể gây nên cản trở. Ví dụ: khi sử dụng các framework như Svelte và file format cụ thể của chúng. Lúc này thì preserveValueImports có thể được sử dụng.

Disabling Import Elision<script>
  import { bookAppointment } from "./appointment.js";
</script>
<button on:click={bookAppointment}>Book</button>

Trong ví dụ trên, TypeScript sẽ loại bỏ import bookAppointment vì nó chỉ "nhìn thấy" code được bọc trong các tags <script />

Type-Only Import Specifiers

Bắt đầu từ phiên bản 3.8, bạn có thể sử dụng rõ ràng type imports bằng cách thêm type vào từ khóa import. Điều này cho trình biên dịch TSC biết rằng việc nhập này chỉ bao gồm các type TypeScript. TSC có thể xóa quá trình import đó sau này.

import type { FC } from 'react';
import { useEffect } from 'react';

Như bạn thấy ở trên, vấn đề là đôi khi bạn cần import statements nếu bạn muốn define cụ thể về các import types. Bạn vẫn có thể làm như sau:

import { FC, useEffect } from 'react';

Nhưng bạn đang "hy sinh" một chút về việc readability (tính dễ đọc). Từ phiên bản 4.5, bạn có thể kết hợp chúng với nhau.

import { type FC, useEffect } from 'react';

Điều đó mang lại sự rõ ràng hơn cho code mà không cần thêm bất kỳ boilerplate nào.

Import Assertions

Tính năng này là việc triển khai các import assertions của ECMAScript proposal. Nó hiện đang ở giai đoạn 3 trong quy trình của ECMAScript.

Nó đảm bảo rằng quá trình import có định dạng mong đợi.

// ✅ regular importYou might want to
import students from "./students.json" assert { type: "json" };
// ✅ dynamic import
const students = await import("./students.json", {
    assert: { type: "json" }
})

TypeScript sẽ không làm bất cứ điều gì trong trường hợp này. Nó sẽ để các trình duyệt và runtime có thể xử lý những điều đó.

Thực nghiệm Module ECMAScript hỗ trợ trong Node.js

Chỉ có sẵn dưới các bản phát hành nightly và có thể thay đổi trong tương lai

Nền tảng module của Node.js là CommonJS. Khi có sự thay đổi đối với các polymorphic app, nhu cầu hỗ trợ các module ECMAScript đã tăng lên. Trong những năm qua, Node.js đã cải thiện để hỗ trợ những điều đó. Từ phiên bản Node 12 trở đi, việc hỗ trợ cho các Module ES đã có sẵn và phổ biến rộng rãi hơn.

Bây giờ có hai cài đặt cấu hình module mới: nodenextnode12.

{
  "compilerOptions": {
    "module": "nodenext"
  }
}

Thuộc tính "type" trong package.json

Trường "type" xác định định dạng module mà Node sẽ được sử dụng cho tất cả các tệp .js mà tệp package.json đó là tệp cha gần nhất của nó. Bạn có thể chọn giữa module cho ES Modules hoặc các commonj cho các CommonJS modules truyền thống.

TypeScript sẽ áp dụng hành vi hệ thống tương tự với các tệp .ts của nó. Khi TypeScript tìm thấy .ts / .tsx / .js / .jsx, nó sẽ xem xét tệp package.json gần nhất để xác định module flavor của nó.

Hệ thống file module tùy chỉnh

Làm thế nào một tệp duy nhất có thể xác định hệ thống module của chính nó? Chỉ cần thay đổi phần mở rộng tệp của nó.

  • .cjs/.cjx: tệp sẽ được nhập ở định dạng CommonJS bất kể cấu hình parent "type" gần nhất.
  • .cts/.ctx/.d.cts: các tệp sẽ được nhập ở định dạng CommonJS bất kể đặc điểm kỹ thuật parent "type" là gì. Khi emitting file, nó sẽ xuất tệp tương ứng của nó . Hãy xem bây giờ chúng ta có thể sử dụng phần mở rộng nào: mjs, .mjx hoặc các khai báo với phần mở rộng .d.cts.
  • .mjs/.mts/.mtx/d.mts: các tệp sẽ được nhập ở định dạng ECMAScript Module bất kể đặc điểm kỹ thuật parent "type" là gì. Khi emitting file, nó sẽ xuất tệp .mjs, .mjx hoặc các khai báo có phần mở rộng .d.mts.

Khả năng tương tác

Bây giờ bạn có thể import các loại module khác nhau bằng cách điều chỉnh hệ thống tệp của nó sao cho cả hai cần phải làm việc cùng nhau. Các ES Module rất dễ dàng vì nó chỉ là một vấn đề của quá trình chuyển đổi. Đối với các ES Module  để import CommonJS, nó sẽ coi chúng như chúng đã export mặc định.

Hãy xem qua ví dụ sau:

// ./foo.cts
export function test() {
  console.log('it works');
}

// ./bar.mts
import { helper } from './foo.cjs';

// prints 'it works'
helper();

Một số điểm rút ra từ ES Modules:

  • Feature:  Sử dụng syntax import/export statement.
  • Feature: top-level await có sẵn với nodenext
  • Caveat: because now there are different module strategies ES Modules relative imports need the full file extension: import fade from ./utils.js
  • Interop: Một số keyword toàn cầu như require sẽ không hoạt động trên ES Modules
  • Interop: CommonJS sẽ truyền tải các tính năng ES như syntax import/export

Resolving @typescript[lib] trong node_modules

TypeScript gói các thư viện nhất định để đảm bảo nó hoạt động tốt cùng với Javascript. Tuy nhiên, bạn có thể muốn thay đổi chúng thành một kiểu triển khai thư viện khác.

  • lib.dom.d.ts -> @typescript/dom
  • lib.dom.iterable.d.ts -> @typescript/dom/iterable
  • lib.es2015.symbol.wellknown.d.ts -> @typescript/es2015/symbol-wellknown

Hãy chọn một phiên bản khác của @stylescript/dom. Ví dụ:

{
  "dependencies": {
    "@typescript/lib-dom": "npm:@types/web"
  }
}

Điều này tương tự như @types, nơi bạn hiện có thể chọn định nghĩa type thích hợp của mình.

Module es2022

TypeScript hiện hỗ trợ cài đặt module mới: es2022. Tính năng đáng chú ý nhất của nó là top-level await. Điều đó cho phép chúng ta sử dụng các hàm await bên ngoài async trong top-level module.

Nó được hỗ trợ bằng cách sử dụng nodenext.

Snippet Completions cho JSX Attributes

Khi viết các component với syntax JSX Typescript thì nó sẽ không tự động gợi ý cho chúng ta. Với snippet completion, điều này hiện đã được giải quyết. Bạn sẽ có được tính năng tự động điền khi viết các component trong ứng dụng React của mình.

Template String Types như Discriminants

Template Literal Type là một tính năng liên tục được trau chuốt kể từ khi phát hành. Là một phần của bản phát hành mới này, giờ đây chúng ta có thể sử dụng các template String types để hoạt động như các discriminant. Trong các phiên bản trước, code sẽ hoạt động nhưng sẽ không có gì xảy ra.

export interface Event {
    type: `${string}Event`;
    read: () => void;
}
export interface Listener {
    type: `${string}Listener`;
    listen: () => void;
}

export function handler(item: Event | Listener) {
    if (item.type === "PushEvent") {
        // ✅ item is of type Event in this scope
        item.read();
    }
}

Kết

Mặc dù đã có một nỗ lực rất lớn để hỗ trợ các ES Modules trong Node.js, nhưng quyết định đó là hơi vội vàng. Tính năng này vẫn cần một số bit để hoàn thiện. Với bản phát hành thử nghiệm, nhóm TypeScript sẽ có cơ hội thu thập phản hồi sớm. Điều này có thể chính thức được thúc đẩy trong bản phát hành tiếp theo.

Thật tuyệt khi thấy rằng các template String types vẫn đang ngày càng tốt hơn. Các công cụ sửa đổi type trên import name sẽ thực sự hữu ích. Quá dài dòng để thêm các import cụ thể cho các type.

You've successfully subscribed to 200Lab Blog
Great! Next, complete checkout for full access to 200Lab Blog
Xin chào mừng bạn đã quay trở lại
OK! Tài khoản của bạn đã kích hoạt thành công.
Success! Your billing info is updated.
Billing info update failed.
Your link has expired.