1

Personal learning is the main thing, and it is convenient for others by the way.😉

address: 161b69bccec769 https://github.com/any86/ts-log-cn, content of this article will continue to be updated.

🔥 Reading notes

Due to limited personal ability, this article only screens type/grammar from the "typescript update log". Versions before 3.1 are all basic knowledge, so only part of the content is extracted. If there are errors, please feel free A lot of pointers and help.

Note : Type inference changes (relaxed/narrowed) and configuration items and ECMA's new syntax selection.

v4.5

New Await type

Get the value type of Prmoise's resolve

// Promise<number>
const p = Promise.resolve(123);
// Awaited<Promise<number>> === number
type B = Awaited<typeof p>;

// 类型参数不是Promise类型,
// 那么不处理, 直接返回
type S = Awaited<string>; // string

Import the name modifier "type"

The previous version supports the syntax of "import type {xx} from'xxx'", and now it supports marking a single import item with "type".

import { someFunc, type BaseType } from "./some-module.js";

Check whether the private attributes of the class exist

Synchronously compatible with ecma syntax

class Person {
    #name: string;
    constructor(name: string) {
        this.#name = name;
    }
    equals(other: unknown) {
        return other &&
            typeof other === "object" &&
            #name in other && // <- 🔥新语法
            this.#name === other.#name;
    }
}

Import assertion

Synchronously compatible with ecma syntax, run-time judgments on imported files, ts does not make any judgments.

import obj from "./something.json" assert { type: "json" };

There is also the syntax of the "import" function:

const obj = await import("./something.json", {
  assert: { type: "json" },
});

v4.4

Type protection is smarter

Common types of protection are as follows:

function nOrs() {
  return Math.random() > 0.5 ? 123 : "abc";
}
let input = nOrs();
if (typeof input === "number") {
  input++;
}

If typeof input === 'number' abstracted into a variable, the type protection will be invalid before version 4.4, but in 4.4 ts can be correctly type protected.

function nOrs() {
  return Math.random() > 0.5 ? 123 : "abc";
}
const input = nOrs();
const isNumber = typeof input === "number";
if (isNumber) {
  // 失效,无法知道input是number类型
  input++;
}

Note : The protected variable must be "const variable" or "realdonly attribute", such as the input above and the "n" attribute below.

interface A {
  readonly n: number | string;
}

const a: A = { n: Math.random() > 0.5 ? "123" : 321 };
const isNumber = typeof a.n === "number";
if (isNumber) {
  // r是number
  const r = a.n;
}

Type protection deeper

Through the judgment of attributes, the range of joint types can be narrowed.

type Shape =
  | { kind: "circle"; radius: number }
  | { kind: "square"; sideLength: number };

function area(shape: Shape): number {
  const isCircle = shape.kind === "circle";
  if (isCircle) {
    // We know we have a circle here!
    return Math.PI * shape.radius ** 2;
  } else {
    // We know we're left with a square here!
    return shape.sideLength ** 2;
  }
}

⚡ Added support for symbol type as object type key

Previously, only "string | number" was supported, which caused an incomplete description of the keys of the Object type. Now it is resolved.

interface Test1 {
  [k: string | number | symbol]: any;
}

type Test2 = {
  [k in string | number | symbol]: any;
};

Static block in class

Synchronous support es new syntax

class Foo {
  static #count = 0;

  get count() {
    return Foo.#count;
  }

  static {
    try {
      const lastInstances = loadLastInstances();
      Foo.#count += lastInstances.length;
    } catch {}
  }
}

v4.3

override keyword

"override" is the syntax provided for the class to mark whether the attribute/method in the subclass overrides the attribute/method with the same name in the parent class.

class A {}

class B extends A {
  // 提示不能用override, 因为基类中没有"a"字段.
  override a() {}
}

@Link in the comment

Click to jump to the specified code.

/**
 * To be called 70 to 80 days after {@link plantCarrot}.
 */
function harvestCarrot(carrot: Carrot) {}
/**
 * Call early in spring for best results. Added in v2.1.0.
 * @param seed Make sure it's a carrot seed!
 */
function plantCarrot(seed: Seed) {
  // TODO: some gardening
}

v4.2

Yuanzu supports optional symbols

let c: [string, string?] = ["hello"];
c = ["hello", "world"];

The primitive type definition supports the use of "..." at any position

But it is required that optional elements (?) and "..." cannot appear at the end

let foo: [...string[], number];

foo = [123];
foo = ["hello", 123];
foo = ["hello!", "hello!", "hello!", 123];

let bar: [boolean, ...string[], boolean];

bar = [true, false];
bar = [true, "some text", false];
bar = [true, "some", "separated", "text", false];

error example

let StealersWheel: [...Clown[], "me", ...Joker[]];
// A rest element cannot follow another rest element.

let StringsAndMaybeBoolean: [...string[], boolean?];
// An optional element cannot follow a rest element.

v4.1

Template string type

The syntax is the same as the usage of "``" in es6, except that it is used to wrap the type:

type World = "world";
// hello world
type Greeting = `hello ${World}`;

type Color = "red" | "blue";
type Quantity = "one" | "two";
// "one fish" | "two fish" | "red fish" | "blue fish"
type SeussFish = `${Quantity | Color} fish`;

New string type

Added Uppercase / Lowercase / Capitalize / Uncapitalize types to the ts system

// ABC
type S1 = Uppercase<"abc">;
// abc
type S2 = Lowercase<"ABC">;
// Abc
type S3 = Capitalize<"abc">;
// aBC
type S4 = Uncapitalize<"ABC">;

Use as in the key in structure

After obtaining the key, it is used to obtain the value, but the key is not used, only the value is used, and then the key is relabeled.

type PPP<T> = {
  [K in keyof T as "ww"]: T[K];
};

// type A = {ww:1|'2'}
type A = PPP<{ a: 1; b: "2" }>;

v4.0

Yuanzu’s rest item can be accurately derived

Previously get the type of the tuple except the first element:

function tail<T extends any[]>(arr: readonly [any, ...T]) {
  const [_ignored, ...rest] = arr;
  return rest;
}

const myTuple = [1, 2, 3, 4] as const;
const myArray = ["hello", "world"];

const r1 = tail(myTuple);
// const r1: [2, 3, 4]
const r2 = tail([...myTuple, ...myArray] as const);
// const r2: [2, 3, 4, ...string[]]

The rest element can appear anywhere in the tuple, not just at the end!

It is required that the element after "..." must be a tuple, and only the last element can be "..."+"array"

type Strings = [string, string];
type Numbers = [number, number];
type StrStrNumNumBool = [...Strings, ...Numbers, boolean];
type StrStrNumNumBool = [...[string], string, ...string[]];

Tuple elements support tagged

It is mainly for compatibility with the definition of function parameters, because function parameters all have parameter names.

type Range = [start: number, end: number];

The assignment of the constructor in the class can directly deduce the type of the attribute

When defining attributes, you can omit the type annotations.

class A {
  // 此时a直接被推导出是number类型
  // 类型可以省略, a不能省略
  a;
  constructor() {
    this.a = 1;
  }
}

The catch parameter in try/catch becomes unknown type

It needs to be judged or asserted before use.

try {
  // ...
} catch (e) {
  e; // unknown
}

/*_ @deprecated _/

Deprecated.

v3.9

// @ts-expect-error

Used to shield errors, different from the motivation of "// @ts-ignore", the main use scenario of "// @ts-expect-error" is that you deliberately made mistakes, such as test cases.

function doStuff(abc: string, xyz: string) {
  assert(typeof abc === "string");
  assert(typeof xyz === "string");
}

// 你想测试传入数字参数, 但是ts会自动推断错误, 这不是你想要的, 所以加"// @ts-expect-error"
expect(() => {
  // @ts-expect-error
  doStuff(123, 456);
}).toThrow();

v3.8

import type / export type

Added new syntax for type-only import and export.

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

Class private attribute "#"

The private attribute syntax of synchronous ecma is different from the private modifier. The private attributes after # cannot be accessed outside the class even after being compiled into js.

class Person {
  #name: string;
  constructor(name: string) {
    this.#name = name;
  }
  greet() {
    console.log(`Hello, my name is ${this.#name}!`);
  }
}

export * as ns

Export grammar, synchronized with ecma2020 grammar

export * as utilities from "./utilities.js";

Await keyword for top-level scope

Synchronous to the ecma syntax, it must be used within the module, so at least there must be an "empty export (export {})"

const response = await fetch("...");
const greeting = await response.text();
console.log(greeting);
// Make sure we're a module
export {};

Another limitation is the configuration item: "target" is above es2017 and "module" is "esnext"

v3.4

readonlyArray

Read-only array

function foo(arr: ReadonlyArray<string>) {
  arr.slice(); // okay
  arr.push("hello!"); // error!
}

readonly T[]

Same effect as readonlyArray.

function foo(arr: readonly string[]) {
  arr.slice(); // okay
  arr.push("hello!"); // error!
}

readonly ancestor

function foo(pair: readonly [string, string]) {
  console.log(pair[0]); // okay
  pair[1] = "hello!"; // error
}

const assertion

After using const assertion, the inferred types are all "unmodifiable".

// Type '"hello"',不能修改x的值了
let x = "hello" as const;
// Type 'readonly [10, 20]'
let y = [10, 20] as const;
// Type '{ readonly text: "hello" }'
let z = { text: "hello" } as const;

You can also write assertions using sharp corners:

// Type '"hello"'
let x = <const>"hello";
// Type 'readonly [10, 20]'
let y = <const>[10, 20];
// Type '{ readonly text: "hello" }'
let z = <const>{ text: "hello" };

Note that the const assertion can only be applied immediately to simple literal expressions.

// Error! A 'const' assertion can only be applied to a
// to a string, number, boolean, array, or object literal.
let a = (Math.random() < 0.5 ? 0 : 1) as const;
let b = (60 * 60 * 1000) as const;
// Works!
let c = Math.random() < 0.5 ? (0 as const) : (1 as const);
let d = 3_600_000 as const;

v3.2

bigint type

bigint is part of ECMAScript's upcoming proposal.

let foo: bigint = BigInt(100); // the BigInt function
let bar: bigint = 100n; // a BigInt literal

v3.1

typesVersions

A project supports multiple declaration files. For example, if the version below is greater than 3.1, go to the "ts3.1" folder under the project to find the declaration file.

// tsconfig.js
{
    "typesVersions": {
        ">=3.1": { "*": ["ts3.1/*"] }
        ">=3.2": { "*": ["ts3.2/*"] }
    }
}

v2.9

import type

New --declarationMap

With --declaration enabled together with --declarationMap, the compiler will generate .d.ts.map at the same time as it generates .d.ts. The language service can now also understand these map files and map the declaration files to the source code.

In other words, clicking go-to-definition in the .d.ts file generated after enabling --declarationMap will navigate to the location in the source file (.ts) instead of navigating to the .d.ts file .

v2.8

-/+

Add and delete readonly/? modifiers.

type MutableRequired<T> = { -readonly [P in keyof T]-?: T[P] }; // 移除readonly和?
type ReadonlyPartial<T> = { +readonly [P in keyof T]+?: T[P] }; // 添加readonly和?

v2.7

let x!: number[];

The initialized variable directly asserts that it has been assigned.

// 没有这!, 会提示"在赋值前不能进行操作"
let x!: number[];
// 这个函数的赋值ts是检测不到的, 所以上一行用了"!"
initialize();
x.push(4);

function initialize() {
  x = [0, 1, 2, 3];
}

v2.6

Chinese tsc

tsc --locale zh-cn

The following command line prompts will be displayed in Chinese.

@ts-ignore

@ts-ignore annotation hides the next line of error

if (false) {
  // @ts-ignore:无法被执行的代码的错误
  console.log("hello");
}

v2.5

Catch in try/catch can omit parameters

let input = "...";
try {
  JSON.parse(input);
} catch {
  // ^ 注意我们的 `catch` 语句并没有声明一个变量
  console.log("传入的 JSON 不合法\n\n" + input);
}

v2.4

Dynamic import, many packaging tools already support import to load modules asynchronously.

Note: The target module in tsconfig needs to be set to "esnext".

async function getZipFile(name: string, files: File[]): Promise<File> {
  const zipUtil = await import("./utils/create-zip-file");
  const zipContents = await zipUtil.getContentAsBlob(files);
  return new File(zipContents, name);
}

v2.3

@ts-nocheck

Use the "// @ts-nocheck" annotation to declare that the file does not check the type.

// @ts-nocheck
let a;
// 本应该提示a未赋值.
a.push(123);

v2.0

Shortcut external module declaration

When you use a new module, if you don't want to spend time writing a statement, you can now use the shortcut statement to get started quickly.

// xxx.d.ts
declare module "hot-new-module";

All imports are of type any

// x,y 都是any
import x, { y } from "hot-new-module";
x(y);

Wildcard in module name

This vue-initialized project has it, and it is used to declare that the .vue file is a component.

declare module "*.vue" {
  import { DefineComponent } from "vue";
  // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
  const component: DefineComponent<{}, {}, any>;
  export default component;
}

and:

declare module "*!text" {
  const content: string;
  export default content;
}
// Some do it the other way around.
declare module "json!*" {
  const value: any;
  export default value;
}

WeChat group

b0413758b722264bb1aa67752d3687f.jpg

Thank you for reading. If you have any questions, you can add me to WeChat. I will pull you into the WeChat group (due to Tencent’s 100-member limit on WeChat groups, group members must be pulled in after more than 100 people)

github

My personal open source is based on ts, welcome everyone to visit https://github.com/any86


铁皮饭盒
5k 声望1.2k 粉丝

喜欢写程序: [链接]