1.TypeScript 概念

TypeScript(简称 TS,静态类型)是微软公司开发的一种基于 JavaScript (简称 JS,动态类型)语言的编程语言。TypeScript 可以看成是 JavaScript 的超集(superset),即它继承了后者的全部语法,增加了一些自己的语法。使用TypeScript可以帮助开发人员在编码过程中避免一些常见的错误,并提供更好的代码编辑功能和工具支持。

2.数据类型

基础类型

  • number: 表示数字,包括整数和浮点数。
  • bigint: 表示大整数。
  • string: 表示文本字符串。
  • boolean: 表示布尔值。
  • null、undefined: 分别表示null和undefined。
  • symbol: 表示唯一的、不可变的值。

复合类型

  • array: 表示数组,可以使用number[]Array<number>来声明其中元素的类型。
  • tuple: 表示元组,用于表示固定数量和类型的数组。
  • enum: 表示枚举类型,用于定义具名常量集合。

对象类型

  • object: 表示非原始类型,即除number、string、boolean、symbol、null或undefined之外的类型。
  • interface: 用于描述对象的结构,并且可以重复使用。

函数类型

  • function: 表示函数类型。
  • void: 表示函数没有返回值。

高级类型

  • union types: 联合类型,表示一个值可以是几种类型之一。
  • intersection types: 交叉类型,表示一个值同时拥有多种类型的特性。

顶层类型

  • any: 表示任意类型。
  • unknown: 严格版的 any 类型。

底层类型

  • never: 类型表示的是那些永不存在的值的类型。

3.基础用法

类型声明

变量只有赋值后才能使用,否则就会报错

let x: number;
console.log(x); // 报错

只读数组

const arr: readonly number[] = [0, 1];// TypeScript 提供了两个专门的泛型,用来生成只读数组的类型
const a1: ReadonlyArray<number> = [0, 1];
const a2: Readonly<number[]> = [0, 1];

只读对象

// 方式一
const myUser: {readonly name: string;
} = {name: 'Sabrina',
};// 方式二
const myUser = {name: 'Sabrina',
} as const;

元组

元组表示成员类型可以自由设置的数组,即数组的各个成员的类型可以不同。

// 数组
let a: number[] = [1];// 元组
let t: [number] = [1];// 元组成员的类型可以添加问号后缀(?),表示该成员是可选的
let a: [number, number?] = [1];// 使用扩展运算符(...),可以表示不限成员数量的元组
type NamedNums = [string, ...number[]];
const a: NamedNums = ['A', 1, 2];

只读元组

// 写法一
type t = readonly [number, string];// 写法二
type t = Readonly<[number, string]>;

包装对象类型与字面量类型

'hello' // 字面量
new String('hello') // 包装对象

TypeScript 对五种原始类型分别提供了大写和小写两种类型。

  • Boolean 和 boolean
  • String 和 string
  • Number 和 number
  • BigInt 和 bigint
  • Symbol 和 symbol

其中,大写类型同时包含包装对象和字面量两种情况,小写类型只包含字面量。

const s1:String = 'hello'; // 正确
const s2:String = new String('hello'); // 正确const s3:string = 'hello'; // 正确
const s4:string = new String('hello'); // 报错

建议只使用小写类型,不使用大写类型。TypeScript 把很多内置方法的参数,定义成小写类型,使用大写类型会报错。

Object 类型与 object 类型

大写的 Object 类型代表 JavaScript 语言里面的广义对象。所有可以转成对象的值(null、undefined除外),都是 Object 类型,这囊括了几乎所有的值。

另外,空对象{}是 Object 类型的简写形式。

小写的 object 类型代表 JavaScript 里面的狭义对象,即可以用字面量表示的对象,只包含对象、数组和函数,不包括原始类型的值。

注意,无论是大写的 Object 类型,还是小写的 object 类型,都只包含 JavaScript 内置对象原生的属性和方法,用户自定义的属性和方法都不存在于这两个类型之中。

const o1:Object = { foo: 0 };
const o2:object = { foo: 0 };o1.toString() // 正确
o1.foo // 报错o2.toString() // 正确
o2.foo // 报错

值类型

TypeScript 规定,单个值也是一种类型,称为“值类型”。

let x:'hello';x = 'hello'; // 正确
x = 'world'; // 报错// 遇到const命令声明的变量,如果代码里面没有注明类型,就会推断该变量是值类型
// x 的类型是 "https"
const x = 'https';

联合类型

联合类型(union types)指的是多个类型组成的一个新类型,使用符号|表示。

let x:string|number;// 值类型相结合
let setting:true|false;// 联合类型的第一个成员前面,也可以加上竖杠|,便于多行书写
let x:| 'one'| 'two'| 'three';

如果一个变量有多种类型,读取该变量时,需要进行“类型缩小”

function printId(id:number|string
) {if (typeof id === 'string') {console.log(id.toUpperCase());} else {console.log(id);}
}

交叉类型

交叉类型(intersection types)指的多个类型组成的一个新类型,使用符号&表示。

// 交叉类型的主要用途是表示对象的合成
let obj: { foo: string } & { bar: string };
obj = {foo: 'hello',bar: 'world',
};// 交叉类型常常用来为对象类型添加新属性
type A = { foo: number };
type B = A & { bar: number };

type 命令

type命令用来定义一个类型的别名。

type Age = number;

别名可以让类型的名字变得更有意义,也能增加代码的可读性,还可以使复杂类型用起来更方便

别名不允许重名。

type Color = 'red';
type Color = 'blue'; // 报错

别名的作用域是块级作用域。这意味着,代码块内部定义的别名,影响不到外部。

type Color = 'red';
if (Math.random() < 0.5) {type Color = 'blue';
}

别名支持使用表达式。

type World = 'world';
type Greeting = `hello ${World}`;

typeof 运算符

TypeScript 中的 typeof 运算符与 JavaScript 不同,其返回值是该值的 TypeScript 类型。

const a = { x: 0 };
type T0 = typeof a; // { x: number }
type T1 = typeof a.x; // number// typeof 的参数只能是标识符,不能是需要运算的表达式
type T = typeof Date(); // 报错// typeof 命令的参数不能是类型
type Age = number;
type MyAge = typeof Age; // 报错
函数重载

有些函数可以接受不同类型或不同个数的参数,并且根据参数的不同,会有不同的函数行为。这种根据参数类型不同,执行不同逻辑的行为,称为函数重载。

TypeScript 对于“函数重载”的类型声明方法是,逐一定义每一种情况的类型。

function reverse(str: string): string;
function reverse(arr: any[]): any[];// 注意,重载的各个类型描述与函数的具体实现之间,不能有其他代码,否则报错
// 另外,类型最宽的声明应该放在最后面

构造函数

class Animal {numLegs: number = 4;
}type AnimalConstructor = new () => Animal;function create(c: AnimalConstructor): Animal {return new c();
}const a = create(Animal);

另一种类型写法,采用对象形式

type F = {new (s: string): object;
};// 某些函数既是构造函数,又可以当作普通函数使用
type F = {new (s: string): object;(n?: number): number;
};

4.接口 interface

interface 是对象的模板,可以看作是一种类型约定,中文译为“接口”。

简介

(1)对象属性

interface IObj {a: number;b?: number; // 可选readonly c: number; // 只读
}

(2)对象的属性索引

interface MyObj {[prop: string]: number;a: boolean; // 报错, 不能为 boolean[prop: number]: string; // 报错, 不能为 string, 与 number 冲突[prop: number]: number; // 正确, 数值属性名会自动转换成字符串属性名
}// 属性的数值索引,可以指定数组的类型
interface A {[prop: number]: string;
}
const obj: A = ['a', 'b', 'c'];

(3)对象的方法

// 写法一
interface A {f(x: boolean): string;
}// 写法二
interface B {f: (x: boolean) => string;
}// 写法三
interface C {f: { (x: boolean): string };
}// 属性名可以采用表达式
const f = 'f';
interface A {[f](x: boolean): string;
}// 类型方法可以重载
interface A {f(): number;f(x: boolean): boolean;f(x: string, y: string): string;
}

(4)函数

interface 也可以用来声明独立的函数。

interface Add {(x: number, y: number): number;
}const myAdd: Add = (x, y) => x + y;

(5)构造函数

interface 内部可以使用 new 关键字,表示构造函数。

interface ErrorConstructor {new (message?: string): Error;
}

继承

(1)interface 继承 interface

interface Style {color: string;
}interface Shape {name: string;
}// 单个继承, 这里 Circle1 是子接口,Shape 是父接口
interface Circle1 extends Shape {radius: number;
}// 多重继承
interface Circle2 extends Style, Shape {radius: number;
}// 子接口与父接口的同名属性必须是类型兼容的
interface Circle1 extends Shape {name: number; // 报错
}
// 多重继承时,如果多个父接口存在同名属性,那么这些同名属性不能有类型冲突

(2)interface 继承 type

type Country = {name: string;capital: string;
};interface CountryWithPop extends Country {population: number;
}
// 注意,如果type命令定义的类型不是对象,interface 就无法继承。

(3)interface 继承 class

class A {x: string = '';y(): boolean {return true;}
}// 继承该类的所有成员
interface B extends A {z: number;
}// 某些类拥有私有(private)成员和保护(protected)成员,interface 可以继承这样的类,
// 但是意义不大,因为私有成员和保护成员只能在类内部访问,无法在类外部使用。

接口合并

多个同名接口会合并成一个接口。

interface Box {height: number;
}
interface Box {width: number;// 属性名相同时, 不能冲突height: string; // 报错, 类型冲突
}// --------------------------
// 对全局对象或者外部库,添加自己的属性和方法
interface Document {foo: string;
}
document.foo = 'hello';// --------------------------
// 同名方法有不同的类型声明,那么会发生函数重载
// 后面的定义比前面的定义具有更高的优先级
interface Cloner {clone(animal: Animal): Animal;
}
interface Cloner {clone(animal: Sheep): Sheep;
}
interface Cloner {clone(animal: Dog): Dog;clone(animal: Cat): Cat;
}
// 等同于
interface Cloner {clone(animal: Dog): Dog;clone(animal: Cat): Cat;clone(animal: Sheep): Sheep;clone(animal: Animal): Animal;
}// 例外:同名方法之中,如果有一个参数是字面量类型,字面量类型有更高的优先级
// 类型越具体, 优先级越高
interface A {f(x: 'foo'): boolean;
}
interface A {f(x: string): void;f(x: any): void;
}
// 等同于
interface A {f(x: 'foo'): boolean;f(x: string): void;f(x: any): void;
}// --------------------------
// 若两个 interface 组成的联合类型存在同名属性,那么该属性的类型也是联合类型
interface Circle {area: bigint;
}
interface Rectangle {area: number;
}
declare const s: Circle | Rectangle;
s.area; // bigint | number

interface 与 type 的异同

很多对象类型既可以用 interface 表示,也可以用 type 表示。

区别有下面几点:

  • (1)type 能够表示非对象类型,而 interface 只能表示对象类型(包括数组、函数等)。
  • (2)interface 可以继承其他类型,type 不支持继承。

继承的主要作用是添加属性,type 定义的对象类型如果想要添加属性,只能使用&运算符,重新定义一个类型。

type Animal = {name: string;
};
type Bear = Animal & {honey: boolean;
};// interface 可以继承 type
type Foo = { x: number };
interface Bar extends Foo {y: number;
}// type 也可以继承 interface
interface Foo {x: number;
}
type Bar = Foo & { y: number };
  • (3)同名 interface 会自动合并,同名 type 则会报错。
  • (4)interface 不能包含属性映射(mapping),type 可以。
interface Point {x: number;y: number;
}
// 正确
type PointCopy1 = {[Key in keyof Point]: Point[Key];
};
// 报错
interface PointCopy2 {[Key in keyof Point]: Point[Key];
};
  • (5)this 关键字只能用于 interface
// 正确
interface Foo {add(num: number): this;
}
// 报错
type Foo = {add(num: number): this;
};
  • (6)type 可以扩展原始数据类型,interface 不行。
// 正确
type MyStr = string & {type: 'new';
};
// 报错
interface MyStr extends string {type: 'new';
}
  • (7)interface 无法表达某些复杂类型(比如交叉类型和联合类型),但是 type 可以。
type A = {/* ... */
};
type B = {/* ... */
};
type AorB = A | B; // 联合类型
// 交叉类型
type AorBwithName = AorB & {name: string;
};

5.类 Class

class Point {readonly x: number;y: number;constructor(x: number, y: number) {this.x = x; // 构造方法内部可以设置只读属性的初值this.y = y;}add(point: Point) {return new Point(this.x + point.x, this.y + point.y);}
}

存取器方法

存取器包括取值器(getter)和存值器(setter)两种方法。

class C {_name = '';get name() {return this._name;}set name(value) {this._name = value;}// 没有set方法,那么该属性自动成为只读属性
}

implements 关键字

interface Country {name: string;capital: string;
}
// 或者
type Country = {name: string;capital: string;
};
// 或者
class Country {name: string;capital: string;
}// 实现接口, 实现多个接口用逗号
class MyCountry implements Country {name = '';capital = '';
}

类与接口的合并

如果一个类和一个接口同名,那么接口会被合并进类。

class A {x: number = 1;
}interface A {y: number;
}let a = new A();
a.y = 10;a.x; // 1
a.y; // 10

Class 实例类型

可以声明类型为 Class,也可以声明类型为 Interface。

interface MotorVehicle {}class Car implements MotorVehicle {}// 写法一
const c1: Car = new Car();
// 写法二
const c2: MotorVehicle = new Car();

类的继承

类(这里又称“子类”)可以使用 extends 关键字继承另一个类(这里又称“基类”)的所有属性和方法。

class A {greet() {console.log('Hello, world!');}
}class B extends A {// 子类可以覆盖基类的同名方法,// 注意, 子类的同名方法不能与基类的类型定义相冲突, 这里参数不能写成必填参数greet(name?: string) {if (name === undefined) {super.greet(); // 调用基类方法} else {console.log(`Hello, ${name}`);}}
}const b = new B();
b.greet(); // "Hello, world!"

可访问性修饰符

类的内部成员的外部可访问性,由三个可访问性修饰符(access modifiers)控制:publicprivateprotected

private修饰符表示私有成员,只能用在当前类的内部,类的实例和子类都不能使用该成员。

protected修饰符表示该成员是保护成员,只能在类的内部使用该成员,实例无法使用该成员,但是子类内部可以使用。

实例属性的简写形式

通过构造方法传入

class Point {x: number;y: number;constructor(x: number, y: number) {this.x = x;this.y = y;}
}

TypeScript 提供了一种简写形式

class Point {constructor(public x: number, public y: number) {}
}

静态成员

类的内部可以使用static关键字,定义静态成员。

静态成员是只能通过类本身使用的成员,不能通过实例对象使用。

class MyClass {static x = 0;static printX() {console.log(MyClass.x);}
}MyClass.x; // 0
MyClass.printX(); // 0

static关键字前面可以使用 public、private、protected 修饰符。

泛型类

class Box<Type> {contents: Type;constructor(value: Type) {this.contents = value;}
}const b: Box<string> = new Box('hello!');

注意,静态成员不能使用泛型的类型参数。

抽象类,抽象成员

在类的定义前面,加上关键字abstract,表示该类不能被实例化,只能当作其他类的模板。这种类就叫做“抽象类”。

abstract class A {id = 1;
}const a = new A(); // 报错

抽象类只能当作基类使用,用来在它的基础上定义子类。

抽象类的内部可以有已经实现好的属性和方法,也可以有还未实现的属性和方法。后者就叫做“抽象成员”(abstract member),即属性名和方法名有 abstract 关键字,表示该方法需要子类实现。如果子类没有实现抽象成员,就会报错。

abstract class A {abstract foo: string;bar: string = '';
}class B extends A {foo = 'b';
}

几个注意点:

  • (1)抽象成员只能存在于抽象类,不能存在于普通类。

  • (2)抽象成员不能有具体实现的代码。

  • (3)抽象成员前也不能有 private 修饰符,否则无法在子类中实现该成员。

  • (4)一个子类最多只能继承一个抽象类。

6.泛型

泛型的特点就是带有“类型参数”(type parameter)。

// <T>,就是类型参数
function getFirst<T>(arr: T[]): T {return arr[0];
}

函数的泛型写法

function id<T>(arg: T): T {return arg;
}// 变量形式定义的函数
// 写法一
let myId: <T>(arg: T) => T = id;// 写法二
let myId: { <T>(arg: T): T } = id;

接口的泛型写法

interface Box<Type> {contents: Type;
}let box: Box<string>;// 泛型接口还有第二种写法
interface Fn {<Type>(arg: Type): Type;
}function id<Type>(arg: Type): Type {return arg;
}let myId: Fn = id;

类的泛型写法

class Pair<K, V> {key: K;value: V;
}

类型别名的泛型写法

type Nullable<T> = T | undefined | null;type Container<T> = { value: T };

类型参数的默认值

function getFirst<T = string>(arr: T[]): T {return arr[0];
}

数组的泛型表示

数组类型有一种表示方法是Array<T>ReadonlyArray<T>接口,表示只读数组。

let arr: Array<number> = [1, 2, 3];let arr: ReadonlyArray<number> = [1, 2, 3];

类型参数的约束条件

// 约束参数必须有 length 属性
function comp<T extends { length: number }>(a: T, b: T) {if (a.length >= b.length) {return a;}return b;
}comp([1, 2], [1, 2, 3]); // 正确
comp('ab', 'abc'); // 正确
comp(1, 2); // 报错

类型参数的约束条件采用下面的形式。

<TypeParameter extends ConstraintType>

类型参数可以同时设置约束条件和默认值,前提是默认值必须满足约束条件。

type Fn<A extends string, B extends string = 'world'> = [A, B];type Result = Fn<'hello'>; // ["hello", "world"]

7.枚举 Enum

简介

Enum 结构,用来将相关常量放在一个容器里面,方便使用。

enum Color {Red, // 0Green, // 1Blue, // 2
}
// 第一个成员的值默认为整数0,第二个为1,第三个为2,以此类推。let c = Color.Green; // 1
// 等同于
let c = Color['Green']; // 1// 类型可以是 Color,也可以是number。
let c: Color = Color.Green; // 正确
let c: number = Color.Green; // 正确// Enum 既是一种类型,也是一个值
// 编译后
let Color = {Red: 0,Green: 1,Blue: 2,
};

Enum 结构比较适合的场景是,成员的值不重要,名字更重要,从而增加代码的可读性和可维护性。

Enum 成员的值

可以为 Enum 成员显式赋值。

// 如果只设定第一个成员的值,后面成员的值就会从这个值开始递增。
enum Color {Red = 7,Green, // 8Blue, // 9
}// 或者
enum Color {Red, // 0Green = 7,Blue, // 8
}

Enum 成员值都是只读的,不能重新赋值。

enum Color {Red,Green,Blue,
}Color.Red = 4; // 报错

在 enum 关键字前面加上 const 修饰,在编译为 JavaScript 代码后,代码中 Enum 成员会被替换成对应的值,不会生成对应的对象,这样能提高性能表现。

const enum Color {Red,Green,Blue,
}const x = Color.Red;
const y = Color.Green;
const z = Color.Blue;// 编译后
const x = 0; /* Color.Red */
const y = 1; /* Color.Green */
const z = 2; /* Color.Blue */

同名 Enum 的合并

多个同名的 Enum 结构会自动合并。

Enum 结构合并时,只允许其中一个的首成员省略初始值,否则报错。

enum Foo {A,
}enum Foo {B, // 报错
}

不能有同名成员,否则报错。

enum Foo {A,B,
}enum Foo {B = 1, // 报错C,
}

同名 Enum 合并的另一个限制是,所有定义必须同为 const 枚举或者非 const 枚举,不允许混合使用。

// 报错
enum E {A,
}
const enum E {B = 1,
}

字符串 Enum

enum Direction {Up = 'UP',Down = 'DOWN',Left = 'LEFT',Right = 'RIGHT',
}

字符串枚举的所有成员值,都必须显式设置。如果没有设置,成员值默认为数值,且位置必须在字符串成员之前。

enum Foo {A, // 0B = 'hello',C, // 报错
}

除了数值和字符串,Enum 成员不允许使用其他值(比如 Symbol 值)。

keyof 运算符

keyof 运算符可以取出 Enum 结构的所有成员名,作为联合类型返回。

enum MyEnum {A = 'a',B = 'b',
}// 'A'|'B'
type Foo = keyof typeof MyEnum;// 返回 Enum 所有的成员值,可以使用in运算符
// { a: any, b: any }
type Foo = { [key in MyEnum]: any };

反向映射

数值 Enum 存在反向映射,即可以通过成员值获得成员名。

enum Weekdays {Monday = 1,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday,
}
console.log(Weekdays[3]); // Wednesday

8.类型断言

简介

type T = 'a' | 'b' | 'c';let foo = 'a';
let bar: T = foo as T; // 正确

类型断言有两种语法。

// 语法一:<类型>值
<Type>value;// 语法二:值 as 类型
value as Type;// 语法一因为跟 JSX 语法冲突,现在一般都使用语法二

类型断言的条件

const n = 1;
const m: string = n as string; // 报错

类型断言的使用前提是,值的实际类型与断言的类型必须满足一个条件:

expr as T;
// expr 是 T 的子类型,或者 T 是 expr 的子类型

如果真的要断言成一个完全无关的类型,需要连续进行两次类型断言,先断言成 unknown 类型或 any 类型,然后再断言为目标类型。因为 any 类型和 unknown 类型是所有其他类型的父类型。

// 或者写成 <T><unknown>expr
expr as unknown as T;

as const 断言

let s = 'JavaScript'; // string 类型type Lang = 'JavaScript' | 'TypeScript' | 'Python'; // 联合类型function setLang(language: Lang) {/* ... */
}setLang(s); // 报错, string 类型(父类型)不能赋值给 Lang 类型(子类型)

报错的解决方法:

// 方法一:
const s = 'JavaScript';// 方法二:
let s = 'JavaScript' as const;
// 使用了 as const 断言以后,let 变量就不能再改变值了

注意,as const 断言只能用于字面量,不能用于变量。

let s = 'JavaScript';
setLang(s as const); // 报错// 另外,as const也不能用于表达式
let s = ('Java' + 'Script') as const; // 报错

as const 也可以写成前置的形式。

// 后置形式
expr as const// 前置形式
<const>expr

as const 断言可以用于整个对象,也可以用于对象的单个属性

const v1 = {x: 1,y: 2,
}; // 类型是 { x: number; y: number; }const v2 = {x: 1 as const,y: 2,
}; // 类型是 { x: 1; y: number; }const v3 = {x: 1,y: 2,
} as const; // 类型是 { readonly x: 1; readonly y: 2; }// 数组
// a1 的类型推断为 number[]
const a1 = [1, 2, 3];// a2 的类型推断为 readonly [1, 2, 3]
const a2 = [1, 2, 3] as const;

由于 as const 会将数组变成只读元组,所以很适合用于函数的 rest 参数

function add(x: number, y: number) {return x + y;
}const nums = [1, 2];
const total = add(...nums); // 报错// 修改后
const nums = [1, 2] as const;
const total = add(...nums); // 正确

Enum 成员也可以使用 as const 断言。

enum Foo {X,Y,
}
let e1 = Foo.X; // Foo
let e2 = Foo.X as const; // Foo.X

非空断言

对于那些可能为空的变量(即可能等于 undefined 或 null),可以使用 !符号,保证这些变量不会为空。

const root = document.getElementById('root'); // 可能为 null// 报错
root.addEventListener('click', (e) => {/* ... */
});// 修改后
const root = document.getElementById('root')!; // 不可能为 null

断言函数

function isString(value: unknown): asserts value is string {if (typeof value !== 'string') throw new Error('Not a string');
}

其中assertsis都是关键词,value是函数的参数名,string是函数参数的预期类型

9.模块

简介

TypeScript 模块除了支持所有 ES 模块的语法,特别之处在于允许输出和输入类型。

// a.ts
export type Bool = true | false;// 也可以写成两行
type Bool = true | false;
export { Bool };// b.ts
// 再另一个文件中引入
import { Bool } from './a';
let foo: Bool = true;

import type 语句

// a.ts
export interface A {foo: string;
}export let a = 123;// b.ts
import { A, a } from './a'; // A 是类型,a 是正常接口

上面写法的问题是,不利于区分类型和正常接口。有两种方法解决:

// 方法一
import { type A, a } from './a';// 方法二, import type 只能输出类型,不能输出正常接口
import type { A } from './a';// 输入默认类型
import type DefaultType from 'moduleA';
// 输入所有类型
import type * as TypeNS from 'moduleA';

CommonJS 模块

使用import =语句和require()命令输入了一个 CommonJS 模块

import fs = require('fs');// 或者
import * as fs from 'fs';

10.装饰器

简介

装饰器(Decorator)是一种语法结构,用来在定义时修改类(class)的行为。

装饰器有如下几个特征:

  • (1)第一个字符(或者说前缀)是@,后面是一个表达式。
  • (2)@后面的表达式,必须是一个函数(或者执行后可以得到一个函数)。
  • (3)这个函数接受所修饰对象的一些相关值作为参数。
  • (4)这个函数要么不返回值,要么返回一个新对象取代所修饰的目标对象。
function simpleDecorator(value: any, context: any) {console.log(`hi, this is ${context.kind} ${context.name}`);return value;
}@simpleDecorator
class A {} // "hi, this is class A"

函数simpleDecorator()用作装饰器,附加在类A之上,后者在代码解析时就会打印一行日志。

装饰器一般只用来为类添加某种特定行为。

@frozen
class Foo {@configurable(false)@enumerable(true)method() {}@throttle(500)expensiveMethod() {}
}

上面示例中,一共有四个装饰器,一个用在类本身(@frozen),另外三个用在类的方法(@configurable@enumerable@throttle)。

装饰器的结构

装饰器函数的类型定义如下。

type Decorator = (value: DecoratedValue,context: {kind: string;name: string | symbol;addInitializer?(initializer: () => void): void;static?: boolean;private?: boolean;access: {get?(): unknown;set?(value: unknown): void;};}
) => void | ReplacementValue;

上面代码中,Decorator是装饰器的类型定义。它是一个函数,使用时会接收到valuecontext两个参数。

  • value:所装饰的对象。
  • context:上下文对象,TypeScript 提供一个原生接口ClassMethodDecoratorContext,描述这个对象。

context对象的属性,根据所装饰对象的不同而不同,其中只有两个属性(kindname)是必有的,其他都是可选的。

(1)kind:字符串,表示所装饰对象的类型,可能取以下的值。

  • ‘class’
  • ‘method’
  • ‘getter’
  • ‘setter’
  • ‘field’
  • ‘accessor’

(2)name:字符串或者 Symbol 值,所装饰对象的名字,比如类名、属性名等。

(3)addInitializer():函数,用来添加类的初始化逻辑。以前,这些逻辑通常放在构造函数里面,对方法进行初始化,现在改成以函数形式传入 addInitializer()方法。注意,addInitializer()没有返回值。

(4)private:布尔值,表示所装饰的对象是否为类的私有成员。

(5)static:布尔值,表示所装饰的对象是否为类的静态成员。

(6)access:一个对象,包含了某个值的 get 和 set 方法。

类装饰器

类装饰器的类型描述如下。

type ClassDecorator = (value: Function,context: {kind: 'class';name: string | undefined;addInitializer(initializer: () => void): void;}
) => Function | void;

方法装饰器

方法装饰器的类型描述如下。

type ClassMethodDecorator = (value: Function,context: {kind: 'method';name: string | symbol;static: boolean;private: boolean;access: { get: () => unknown };addInitializer(initializer: () => void): void;}
) => Function | void;

属性装饰器

类型描述如下

type ClassFieldDecorator = (value: undefined,context: {kind: 'field';name: string | symbol;static: boolean;private: boolean;access: { get: () => unknown, set: (value: unknown) => void };addInitializer(initializer: () => void): void;}
) => (initialValue: unknown) => unknown | void;

getter 装饰器,setter 装饰器

类型描述如下

type ClassGetterDecorator = (value: Function,context: {kind: 'getter';name: string | symbol;static: boolean;private: boolean;access: { get: () => unknown };addInitializer(initializer: () => void): void;}
) => Function | void;type ClassSetterDecorator = (value: Function,context: {kind: 'setter';name: string | symbol;static: boolean;private: boolean;access: { set: (value: unknown) => void };addInitializer(initializer: () => void): void;}
) => Function | void;

11.declare

简介

declare 关键字用来告诉编译器,某个类型是存在的,可以在当前文件中使用。
declare 关键字可以描述以下类型。

  • 变量(const、let、var 命令声明)
  • type 或者 interface 命令声明的类型
  • class
  • enum
  • 函数(function)
  • 模块(module)
  • 命名空间(namespace)

declare variable

declare 关键字可以给出外部变量的类型描述。

其他脚本定义的全局变量x,使用 declare 命令给出它的类型。

declare let x:number;
x = 1; // 声明类型后使用就不会再报错

declare function

declare 关键字可以给出外部函数的类型描述。

declare function sayHello(name: string): void;sayHello('张三');

declare class

declare class Animal {constructor(name: string);eat(): void;sleep(): void;
}

declare module,declare namespace

如果想把变量、函数、类组织在一起,可以将 declare 与 module 或 namespace 一起使用。

declare namespace AnimalLib {class Animal {constructor(name: string);eat(): void;sleep(): void;}type Animals = 'Fish' | 'Dog';
}// 或者
declare module AnimalLib {class Animal {constructor(name: string);eat(): void;sleep(): void;}type Animals = 'Fish' | 'Dog';
}

declare module 和 declare namespace 里面,加不加 export 关键字都可以。

declare global

如果要为 JavaScript 引擎的原生对象添加属性和方法,可以使用declare global {}语法。

export {};declare global {interface String {toSmallString(): string;}
}String.prototype.toSmallString = (): string => {// 具体实现return '';
};

上面示例中,为 JavaScript 原生的String对象添加了toSmallString()方法。declare global 给出这个新增方法的类型描述。

这个示例第一行的空导出语句export {},作用是强制编译器将这个脚本当作模块处理。这是因为 declare global 必须用在模块里面。

declare enum

declare enum E1 {A,B,
}declare enum E2 {A = 0,B = 1,
}declare const enum E3 {A,B,
}declare const enum E4 {A = 0,B = 1,
}

12. d.ts 类型声明文件

简介

单独使用的模块,一般会同时提供一个单独的类型声明文件(declaration file),把本模块的外部接口的所有类型都写在这个文件里面,便于模块使用者了解接口,也便于编译器检查使用者的用法是否正确。

文件名一般为[模块名].d.ts的形式,其中的d表示 declaration(声明)。

类型声明文件的来源

类型声明文件主要有以下三种来源。

  • TypeScript 编译器自动生成。
  • TypeScript 内置类型文件。
  • 外部模块的类型声明文件,需要自己安装。

1.自动生成

只要使用编译选项 declaration,编译器就会在编译时自动生成单独的类型声明文件。

下面是在tsconfig.json文件里面,打开这个选项。

{"compilerOptions": {"declaration": true}
}

2.内置声明文件

安装 TypeScript 语言时,会同时安装一些内置的类型声明文件,这些内置声明文件位于 TypeScript 语言安装目录的 lib 文件夹内。例如:

  • lib.d.ts
  • lib.dom.d.ts
  • lib.es2015.d.ts
  • lib.es2016.d.ts
  • lib.es2017.d.ts
  • lib.es2018.d.ts
  • lib.es2019.d.ts
  • lib.es2020.d.ts
  • lib.es5.d.ts
  • lib.es6.d.ts

TypeScript 编译器会自动根据编译目标 target 的值,加载对应的内置声明文件,所以不需要特别的配置。可以使用编译选项 lib,指定加载哪些内置声明文件。

{"compilerOptions": {"lib": ["dom", "es2021"]}
}

3.外部模块的类型声明文件

如果项目中使用了外部的某个第三方代码库,那么就需要这个库的类型声明文件。

分成三种情况。

(1)这个库自带了类型声明文件。

一般来说,如果这个库的源码包含了[vendor].d.ts文件,那么就自带了类型声明文件。

(2)这个库没有自带,但是可以找到社区制作的类型声明文件。

第三方库如果没有提供类型声明文件,社区往往会提供。如:"@types/jquery"

TypeScript 会自动加载node_modules/@types目录下的模块,但可以使用编译选项typeRoots改变这种行为。

{"compilerOptions": {"typeRoots": ["./typings", "./vendor/types"]}
}

上面示例表示,TypeScript 不再去node_modules/@types目录,而是去跟当前tsconfig.json同级的typingsvendor/types子目录,加载类型模块了。

默认情况下,TypeScript 会自动加载typeRoots目录里的所有模块,编译选项types可以指定加载哪些模块。

{"compilerOptions": {"types": ["jquery"]}
}

(3)找不到类型声明文件,需要自己写。

有时实在没有第三方库的类型声明文件,又很难完整给出该库的类型描述,这时你可以告诉 TypeScript 相关对象的类型是any

declare var $: any;// 或者
declare type JQuery = any;
declare var $: JQuery;

模块发布

当前模块如果包含自己的类型声明文件,可以在 package.json 文件里面添加一个types字段或typings字段,指明类型声明文件的位置。

{"name": "awesome","author": "Vandelay Industries","version": "1.0.0","main": "./lib/main.js","types": "./lib/main.d.ts"
}

三斜杠命令

如果类型声明文件的内容非常多,可以拆分成多个文件,然后入口文件使用三斜杠命令,加载其他拆分后的文件。

举例来说,入口文件是main.d.ts,里面的接口定义在interfaces.d.ts,函数定义在functions.d.ts。那么,main.d.ts里面可以用三斜杠命令,加载后面两个文件。

/// <reference path="./interfaces.d.ts" />
/// <reference path="./functions.d.ts" />

注意,三斜杠命令只能用在文件的头部,如果用在其他地方,会被当作普通的注释。

三斜杠命令主要包含三个参数,代表三种不同的命令。

  • path
  • types
  • lib

1./// <reference path="" />

告诉编译器在编译时需要包括的文件,常用来声明当前脚本依赖的类型文件。

/// <reference path="./lib.ts" />let count = add(1, 2);

上面示例表示,当前脚本依赖于./lib.ts,里面是add()的定义。编译当前脚本时,还会同时编译./lib.ts。编译产物会有两个 JS 文件,一个当前脚本,另一个就是./lib.js

2./// <reference types="" />

types 参数用来告诉编译器当前脚本依赖某个 DefinitelyTyped 类型库,通常安装在node_modules/@types目录。

/// <reference types="node" />

上面示例中,这个三斜杠命令表示编译时添加 Node.js 的类型库,实际添加的脚本是 node_modules 目录里面的@types/node/index.d.ts

/// <reference lib="" />

允许脚本文件显式包含内置 lib 库,等同于在tsconfig.json文件里面使用 lib 属性指定 lib库。

13.TypeScript 类型运算符

keyof 运算符

keyof 是一个单目运算符,接受一个对象类型作为参数,返回该对象的所有键名组成的联合类型。

type MyObj = {foo: number;bar: string;
};type Keys = keyof MyObj; // 'foo'|'bar'

由于 JavaScript 对象的键名只有三种类型,所以对于任意对象的键名的联合类型就是string|number|symbol

// string | number | symbol
type KeyT = keyof any;

对于没有自定义键名的类型使用 keyof 运算符,返回never类型,表示不可能有这样类型的键名。

type KeyT = keyof object; // never

keyof 取出的是键名组成的联合类型,如果想取出键值组成的联合类型,可以像下面这样写。

type MyObj = {foo: number;bar: string;
};type Keys = keyof MyObj;type Values = MyObj[Keys]; // number|string

keyof 运算符往往用于精确表达对象的属性类型。

function prop<Obj, K extends keyof Obj>(obj: Obj, key: K): Obj[K] {return obj[key];
}

上面示例中,K extends keyof Obj表示KObj的一个属性名,传入其他字符串会报错。返回值类型Obj[K]就表示K这个属性值的类型。

keyof 的另一个用途是用于属性映射,即将一个类型的所有属性逐一映射成其他值。

type NewProps<Obj> = {[Prop in keyof Obj]: boolean;
};// 用法
type MyObj = { foo: number };// 等于 { foo: boolean; }
type NewObj = NewProps<MyObj>;

下面的例子是让可选属性变成必有的属性。

type Concrete<Obj> = {[Prop in keyof Obj]-?: Obj[Prop];
};// 用法
type MyObj = {foo?: number;
};// 等于 { foo: number; }
type NewObj = Concrete<MyObj>;

上面示例中,[Prop in keyof Obj]后面的-?表示去除可选属性设置。对应地,还有+?的写法,表示添加可选属性设置。

in 运算符

JavaScript 语言中,in运算符用来确定对象是否包含某个属性名。

const obj = { a: 123 };if ('a' in obj) console.log('found a');

TypeScript 语言的类型运算中,in运算符有不同的用法,用来取出(遍历)联合类型的每一个成员类型。

type U = 'a' | 'b' | 'c';type Foo = {[Prop in U]: number;
};
// 等同于
type Foo = {a: number;b: number;c: number;
};

方括号运算符

方括号运算符([])用于取出对象的键值类型,比如T[K]会返回对象T的属性K的类型。

type Person = {age: number;name: string;alive: boolean;
};// Age 的类型是 number
type Age = Person['age'];

方括号的参数如果是联合类型,那么返回的也是联合类型。

type Person = {age: number;name: string;alive: boolean;
};// number|string
type T = Person['age' | 'name'];// number|string|boolean
type A = Person[keyof Person];

方括号运算符的参数也可以是属性名的索引类型。

type Obj = {[key: string]: number;
};// number
type T = Obj[string];

extends…?: 条件运算符

条件运算符extends...?:可以根据当前类型是否符合某种条件,返回不同的类型。

// 类型T是否可以赋值给类型U,即T是否为U的子类型
T extends U ? X : Y// true
type T = 1 extends number ? true : false;

infer 关键字

infer关键字用来定义泛型里面推断出来的类型参数,而不是外部传入的类型参数。

is 运算符

函数返回布尔值的时候,可以使用is运算符,限定返回值与参数之间的关系。

function isFish(pet: Fish | Bird): pet is Fish {return (pet as Fish).swim !== undefined;
}

上面示例中,函数isFish()的返回值类型为pet is Fish,表示如果参数pet类型为Fish,则返回true,否则返回false

satisfies 运算符

satisfies运算符用来检测某个值是否符合指定类型。

14.类型映射

简介

映射(mapping)指的是,将一种类型按照映射规则,转换成另一种类型,通常用于对象类型。

type A = {foo: number;bar: number;
};type B = {foo: string;bar: string;
};

上面示例中,这两个类型的属性结构是一样的,但是属性的类型不一样。如果属性数量多的话,逐个写起来就很麻烦。

使用类型映射,就可以从类型 A 得到类型 B。

type A = {foo: number;bar: number;
};type B = {[prop in keyof A]: string;
};

具体的计算规则如下:

  • prop:属性名变量,名字可以随便起。
  • in:运算符,用来取出右侧的联合类型的每一个成员。
  • keyof A:返回类型 A 的每一个属性名,组成一个联合类型。

TypeScript 内置的工具类型1Readonly<T>可以将所有属性改为只读属性,实现也是通过映射。

// 将 T 的所有属性改为只读属性
type Readonly<T> = {readonly [P in keyof T]: T[P];
};

映射修饰符

映射会原样复制原始对象的可选属性和只读属性。

type A = {a?: string;readonly b: number;
};type B = {[Prop in keyof A]: A[Prop];
};// 等同于
type B = {a?: string;readonly b: number;
};

TypeScript 引入了两个映射修饰符,用来在映射时添加或移除某个属性的?修饰符和readonly修饰符。

  • +修饰符:写成+?+readonly,为映射属性添加?修饰符或 readonly 修饰符。
  • 修饰符:写成-?-readonly,为映射属性移除?修饰符或 readonly 修饰符。
// 添加可选属性
type Optional<Type> = {[Prop in keyof Type]+?: Type[Prop];
};// 移除可选属性
type Concrete<Type> = {[Prop in keyof Type]-?: Type[Prop];
};// 添加 readonly
type CreateImmutable<Type> = {+readonly [Prop in keyof Type]: Type[Prop];
};// 移除 readonly
type CreateMutable<Type> = {-readonly [Prop in keyof Type]: Type[Prop];
};

TypeScript 原生的工具类型Required<T>专门移除可选属性,就是使用-?修饰符实现的。

另外,+?修饰符可以简写成?+readonly修饰符可以简写成readonly

键名重映射

TypeScript 4.1 引入了键名重映射(key remapping),允许改变键名。

type A = {foo: number;bar: number;
};type B = {[p in keyof A as `${p}ID`]: number;
};// 等同于
type B = {fooID: number;barID: number;
};

属性过滤

键名重映射还可以过滤掉某些属性。下面的例子是只保留字符串属性。

type User = {name: string;age: number;
};type Filter<T> = {[K in keyof T as T[K] extends string ? K : never]: string;
};type FilteredUser = Filter<User>; // { name: string }

它的键名重映射as T[K] extends string ? K : never],使用了条件运算符。如果属性值T[K]的类型是字符串,那么属性名不变,否则属性名类型改为never,即这个属性名不存在。

15.类型工具

  1. Awaited<Type> ,用来取出 Promise 的返回值类型
  2. ConstructorParameters<Type> ,提取构造方法Type的参数类型,组成一个元组类型返回
  3. Exclude<UnionType,ExcludedMembers> ,用来从联合类型UnionType里面,删除某些类型ExcludedMembers,组成一个新的类型返回
  4. Extract<UnionType, Union> ,用来从联合类型UnionType之中,提取指定类型Union,组成一个新类型返回
  5. InstanceType<Type>,提取构造函数的返回值的类型(即实例类型)
  6. NonNullable<Type> ,用来从联合类型Type删除null类型和undefined类型,组成一个新类型返回
  7. Omit<Type, Keys> ,用来从对象类型Type中,删除指定的属性Keys,组成一个新的对象类型返回
  8. OmitThisParameter<Type>,从函数类型中移除 this 参数
  9. Parameters<Type> ,从函数类型Type里面提取参数类型,组成一个元组返回
  10. Partial<Type> ,返回一个新类型,将参数类型Type的所有属性变为可选属性
  11. Pick<Type, Keys> ,返回一个新的对象类型,第一个参数Type是一个对象类型,第二个参数Keys是Type里面被选定的键名
  12. Readonly<Type>,返回一个新类型,将参数类型Type的所有属性变为只读属性
  13. Record<Keys, Type> ,返回一个对象类型,参数Keys用作键名,参数Type用作键值类型
  14. Required<Type> ,返回一个新类型,将参数类型Type的所有属性变为必选属性
  15. ReadonlyArray<Type>,用来生成一个只读数组类型,类型参数Type表示数组成员的类型
  16. ReturnType<Type> ,提取函数类型Type的返回值类型,作为一个新类型返回
  17. ThisParameterType<Type> ,提取函数类型中this参数的类型
  18. ThisType<Type> ,不返回类型,只用来跟其他类型组成交叉类型,用来提示 TypeScript 其他类型里面的this的类型
  19. 字符串类型工具
  • Uppercase<StringType>,将字符串类型的每个字符转为大写
  • Lowercase<StringType>,将字符串的每个字符转为小写
  • Capitalize<StringType>,将字符串的第一个字符转为大写
  • Uncapitalize<StringType>,将字符串的第一个字符转为小写

16.注释指令

// @ts-nocheck

// @ts-nocheck告诉编译器不对当前脚本进行类型检查,可以用于 TypeScript 脚本,也可以用于 JavaScript 脚本。

// @ts-nocheckconst element = document.getElementById(123);

// @ts-check

如果一个 JavaScript 脚本顶部添加了// @ts-check,那么编译器将对该脚本进行类型检查,不论是否启用了checkJs编译选项。

// @ts-check
let isChecked = true;console.log(isChceked); // 报错, 拼写错误

// @ts-ignore

// @ts-ignore告诉编译器不对下一行代码进行类型检查,可以用于 TypeScript 脚本,也可以用于 JavaScript 脚本。

let x: number;x = 0;// @ts-ignore
x = false; // 不报错

// @ts-expect-error

// @ts-expect-error主要用在测试用例,当下一行有类型错误时,它会压制 TypeScript 的报错信息(即不显示报错信息),把错误留给代码自己处理。

JSDoc

TypeScript 直接处理 JS 文件时,如果无法推断出类型,会使用 JS 脚本里面的 JSDoc 注释。

JSDoc 基本要求:

  • JSDoc 注释必须以/**开始,其中星号(*)的数量必须为两个。若使用其他形式的多行注释,则 JSDoc 会忽略该条注释。
  • JSDoc 注释必须与它描述的代码处于相邻的位置,并且注释在上,代码在下。

下面是 JSDoc 的一个简单例子。

/*** @param {string} somebody*/
function sayHello(somebody) {console.log('Hello ' + somebody);
}

TypeScript 编译器支持大部分的 JSDoc 声明,举例如下:

  • @typedef,创建自定义类型,等同于 TypeScript 里面的类型别名。
/*** @typedef {(number | string)} NumberLike*/// 等同于
type NumberLike = string | number;
  • @type,定义变量的类型。
/*** @type {string}*/
let a;// @type定义了变量a的类型为string// 在@type命令中允许使用 TypeScript 类型及其语法。
/**@type {true | false} */
let a;/** @type {number[]} */
let b;/** @type {Array<number>} */
let c;
  • @param,用于定义函数参数的类型。
/*** @param {string}  x*/
function foo(x) {}// 如果是可选参数,需要将参数名放在方括号[]里面
/*** @param {string}  [x]*/
function foo(x) {}// 可以指定参数默认值
/*** @param {string} [x="bar"]*/
function foo(x) {}
  • @return,@returns,两个命令作用相同,指定函数返回值的类型。
/*** @return {boolean}*/
function foo() {return true;
}
  • @extends 和类型修饰符,@extends 命令用于定义继承的基类。
/*** @extends {Base}*/
class Derived extends Base {}// @public、@protected、@private分别指定类的公开成员、保护成员和私有成员。
// @readonly指定只读成员。
class Base {/*** @public* @readonly*/x = 0;/***  @protected*/y = 0;
}

参考文档

  • TypeScript 英文文档
  • TypeScript 翻译的中文文档
  • 网道-阮一峰-TypeScript 教程

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/88778.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/88778.shtml
英文地址,请注明出处:http://en.pswp.cn/web/88778.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

掌握现代CSS:变量、变形函数与动态计算

CSS近年来发展迅速&#xff0c;引入了许多强大的功能&#xff0c;如变量、高级变形函数和动态计算能力。本文将深入探讨如何在CSS中设置并使用变量&#xff0c;以及如何有效利用translate3d、translateY和translateX等变形方法。我们还将解析var()和calc()函数的关键作用。一、…

贝尔量子实验设想漏洞

1 0 1 0 1 1 0 1 0 1 1 1 0 0 1 0 带墨镜如果先上下交换再左右交换&#xff0c;很可能不一样的概率是2%&#xff0c;但是因为交换诞生了一个与之前序列相同的所以不一样概率变成1%&#xff0c;我们在测的时候不能这么测啊&#xff0c;你得看序列完…

在 Android 库模块(AAR)中,BuildConfig 默认不会自动生成 VERSION_CODE 和 VERSION_NAME 字段

为什么AAR库模块的 BuildConfig 没有 versionCode 和 versionName&#xff1f; aar库模块的 BuildConfig 默认不包含版本信息 应用模块&#xff08;com.android.application&#xff09;会自动生成 versionCode 和 versionName 到 BuildConfig。但库模块&#xff08;com.androi…

强化学习 (11)随机近似

计算均值的新方法有两种方法。第一种方法很直接&#xff0c;即收集所有样本后计算平均值&#xff1b;但这种方法的缺点是&#xff0c;若样本是在一段时间内逐个收集的&#xff0c;我们必须等到所有样本都收集完毕。第二种方法可避免此缺点&#xff0c;因为它以增量迭代的方式计…

PHP `implode` 深度解析:从基础到高阶实战指南

文章目录一、基础语法与底层原理执行过程解析&#xff1a;二、性能关键&#xff1a;避免隐含陷阱1. 类型转换黑盒2. 大数组内存优化3. 关联数组处理三、高阶应用场景1. SQL语句安全构建2. CSV文件生成3. 模板引擎实现四、多维数组处理方案1. 递归降维2. JSON转换桥接五、性能对…

开发语言中关于面向对象和面向过程的笔记

开发语言中关于面向对象和面向过程的笔记市面主流语言分类面向过程面向对象市面主流语言分类 面向过程编程&#xff08;Procedural Programming&#xff09;&#xff1a;C语言&#xff1b;面向对象编程语言&#xff08;Object-Oriented Programming, OOP&#xff09; &#xf…

AI产品经理面试宝典第3天:技术分层、边界与市场全景系列面试题

面试指导 面试官:请从技术实现效果的角度,解释AI技术分层。 你的回答: AI技术分为三层。 第一层是认知层:通过图像处理、语音识别、自然语言理解等技术,让机器感知环境。比如摄像头识别行人动作,麦克风捕捉用户指令。 第二层是预测层:基于行为数据预判下一步需求。例如…

Intel英特尔ICH7R/ICH8R/ICH9R/ICH10R系列下载地址--intel_msm_8961002 下载 Version 8.9.6.1002

Intel英特尔ICH7R/ICH8R/ICH9R/ICH10R系列下载地址intel_msm_8961002 下载 Version 8.9.6.1002https://xiazai.zol.com.cn/detail/66/653449.shtml通过网盘分享的文件&#xff1a;intel_msm_8961002.zip 链接: https://pan.baidu.com/s/13N9ZLXWkaWaEHQ5P90Jt0g?pwd3790 提取码…

AI(学习笔记第五课) 使用langchain进行AI开发 load documents(web)

文章目录AI(学习笔记第五课) 使用langchain进行AI开发 load documents(web)学习内容&#xff1a;1.load documents&#xff08;web&#xff09;1.1 学习url1.2 提前安装python的package1.2 使用WebBaseLoader进行webpage的load1.3 使用BeautifulSoup4进行webpage的部分截取1.4 …

使用macvlan实现容器的跨主机通信

使用环境&#xff1a; 两台运行docker的服务器 A机器网段&#xff1a;192.168.86.61 B机器网段&#xff1a;192.168.86.62 运行的容器需装有ping指令&#xff0c; 实验参数解释&#xff1a; -d macvlan 指定创建网络驱动类型 --subnet 指定子网范围 -gateway 指定网关地址 -o p…

深度学习_全连接神经网络

1.什么是神经网络神经网络中信息只向一个方向移动&#xff0c;即从输入节点向前移动&#xff0c;通过隐藏节点&#xff0c;再向输出节点移 动&#xff0c;网络中没有循环或者环。其中的基本构件是&#xff1a; 输入层&#xff1a;即输入x的那一层 输出层&#xff1a;即输出y的那…

OpenLayers使用

初学ol&#xff0c;实现了高德地图不同图层的切换、交互性地图飞行以及加载本地JSON数据。说一下不同图层切换的想法&#xff1a;1.对于标准地图和卫星地图&#xff1a;二者最初便挂载到map上&#xff0c;两个图层是叠加显示的&#xff1b;当点击按钮时&#xff0c;其实是使用 …

day4--上传图片、视频

1. 分布式文件系统 1.1 什么是分布式文件系统 文件系统是负责管理和存储文件的系统软件&#xff0c;操作系统通过文件系统提供的接口去存取文件&#xff0c;用户通过操作系统访问磁盘上的文件。 下图指示了文件系统所处的位置&#xff1a; 常见的文件系统&#xff1a;FAT16/FA…

极矢量与轴矢量

物理量分为标量和矢量&#xff0c;矢量又分为极矢量和轴矢量。 矢量是既有大小又有方向并按平行四边形法则相加的量。矢量有极矢量和轴矢量两种&#xff0c;其间的区别是在镜像反射变换下遵循不同的变换规律,许多物理量都是矢量,同样,其中也有极矢量和轴矢量的区分,在力学中,例…

文章发布易优CMS(Eyoucms)网站技巧

为了更快的上手数据采集及发布到易优CMS(eyoucms)网站&#xff0c;特地总结了些新手常常会遇到的操作问题与技巧&#xff0c;如下&#xff1a; 免费易优CMS采集发布插件下载&#xff0c;兼容火车头、八爪鱼、简数采集等 目录 1. 发布到易优CMS指定栏目 2. 发布文章到易优CM…

INA226 数据手册解读

INA226是一款数字电流检测放大器&#xff0c;配备I2C和SMBus兼容接口。该器件可提供数字电流、电压以及功率读数&#xff0c;可灵活配置测量分辨率&#xff0c;并具备连续运行与触发操作模式。该芯片通常由一个单独的电源供电&#xff0c;电压范围为 2.7V 至 5.5V引脚说明​​引…

Linux 中替换sed

以下是关于 sed&#xff08;Stream Editor&#xff09;的深度详解和日常高频使用场景&#xff0c;结合实用示例说明&#xff1a;一、sed 核心概念 流式编辑器&#xff1a;逐行处理文本&#xff0c;不直接修改源文件&#xff08;除非使用 -i 选项&#xff09;正则支持&#xff1…

ADB 调试日志全攻略:如何开启与关闭 `ADB_TRACE` 日志

ADB 调试日志全攻略&#xff1a;如何开启与关闭 ADB_TRACE 日志 ADB&#xff08;Android Debug Bridge&#xff09;是 Android 开发的核心工具&#xff0c;但在排查问题时&#xff0c;默认日志可能不够详细。通过设置环境变量 ADB_TRACE&#xff0c;可以开启 全量调试日志&…

实现druid数据源密码加密

生成加密密码集成了druid链接池的&#xff0c;可以实现数据源密码加密。加密方式如下构建单元测试&#xff0c;并输入密码即可生成加密密码以及加密公钥Test public void testPwd() throws Exception {String password "123456";String[] arr com.alibaba.druid.fi…

【TCP/IP】20. 因特网安全

20. 因特网安全20. 因特网安全20.1 安全威胁20.2 安全服务20.3 基本安全技术20.3.1 密码技术20.3.2 报文鉴别技术20.3.3 身份认证技术20.3.4 数字签名技术20.3.5 虚拟专用网&#xff08;VPN&#xff09;技术20.3.6 防火墙技术20.3.7 防病毒技术20.4 IP 层安全20.5 传输层安全20…