青训营-深入浅出typescript

148 阅读9分钟

一、为什么要学习ts

ts vs js

TypeScript 是 JavaScript 的超集,它包含了 JavaScript 的所有元素,可以载入 JavaScript 代码运行,并扩展了 JavaScript 的语法。TypeScript 增加了静态类型、类、模块、接口和类型注解等特性。TypeScript 代码需要通过编译器编译为 JavaScript,然后再交由 JavaScript 解析器执行。

image.png

ts带来了什么?

image.png

ts课程推荐

awesome-typescript

www.typescriptlang.org/play

二、ts基础

ts数据类型

  • number 类型用于表示数字,可以是整数或浮点数。例如:let num: number = 123;
  • string 类型用于表示字符串,可以使用单引号或双引号来定义。例如:let str: string = 'hello';
  • boolean 类型用于表示布尔值,只有两个值:truefalse。例如:let isTrue: boolean = true;
  • nullundefined 分别表示空值和未定义。它们的类型分别为 nullundefined。例如:let n: null = null; let u: undefined = undefined;
  • symbol 类型表示独一无二的值。例如:let sym1 = Symbol(); let sym2 = Symbol('key');
  • 数组 类型用于表示一组相同类型的值。可以使用 类型[]Array<类型> 来定义。例如:let arr1: number[] = [1, 2, 3]; let arr2: Array<number> = [1, 2, 3];
  • 对象 类型用于表示一个对象,可以使用接口或类型别名来定义对象的类型。例如:
interface Person {
    name: string;
    age: number;
}
let person: Person = {
    name: 'lisa',
    age: 25
};
  • 枚举(Enum) 类型用于定义一组命名的常数。当一个变量有几种可能的取值时,可以将它定义为枚举类型。例如,我们可以定义一个枚举类型来表示颜色:
enum Color {
    Red,
    Green,
    Blue
}
let c: Color = Color.Green;

在上面的例子中,我们定义了一个名为 Color 的枚举类型,它包含三个成员,分别表示红、绿、蓝三种颜色。然后我们定义了一个名为 c 的变量,它的类型为 Color,并将它的值设置为 Color.Green

枚举成员默认从 0 开始递增,也可以手动指定成员的值:

enum Color {
    Red = 1,
    Green,
    Blue
}
let c: Color = Color.Green;

在上面的例子中,我们将 Red 的值指定为 1,那么后面的成员会依次递增,即 Green 的值为 2Blue 的值为 3

还可以通过枚举值来获取它的名字:

enum Color {
    Red = 1,
    Green,
    Blue
}
let colorName: string = Color[2];
console.log(colorName); // 输出 'Green'

在上面的例子中,我们使用 Color[2] 来获取枚举值为 2 的成员的名字,即 'Green'

  • never 类型表示永不存在的值的类型,常用于抛出异常或无限循环的函数返回值类型。例如:
function error(message: string): never {
    throw new Error(message);
}
  • any 类型表示任意类型,可以赋予任意类型的值。例如:let notSure: any = 6; notSure = 'I am string'; notSure = false;
  • unknown 类型与 any 类型类似,但更安全,因为在对 unknown 类型的值进行操作之前,需要先进行类型判断。例如:
let value: unknown;
value = true;
value = 42;
value = 'hello';
if (typeof value === 'string') {
    console.log(value.toUpperCase());
}
  • void 类型表示没有任何返回值的函数返回值类型。例如:
function warnUser(): void {
    console.log('This is a warning message');
}

元组(Tuple)类型用来表示一个已知元素数量和类型的数组,各元素的类型不必相同。例如,你可以定义一个元组,它包含一个 string 类型元素和一个 number 类型元素:

let tuple: [string, number];
tuple = ['hello', 123]; // OK
tuple = [123, 'hello']; // Error

在上面的例子中,我们定义了一个名为 tuple 的元组类型变量,它包含两个元素,第一个元素的类型为 string,第二个元素的类型为 number。当我们给 tuple 赋值时,需要提供两个元素,并且元素的类型需要与定义时指定的类型一致。

我们可以像访问数组中的元素一样访问元组中的元素,例如:

let tuple: [string, number] = ['hello', 123];
console.log(tuple[0]); // 输出 'hello'
console.log(tuple[1]); // 输出 123

课程中enum的举例子图片

image.png

课程中never的举例子图片

image.png

ts函数类型

在 TypeScript 中,函数类型用于定义函数的参数类型和返回值类型。 定义函数的规则如下图:

image.png 这里解释下老师课上说的函数重载:

函数重载是指根据参数的类型执行不同的函数。多数用于传入不同的参数得到不同的结果。重载分为两个部分(缺一不可):声明和实现。

举个例子,假设我们有一个函数,可以接收string类型相拼接,也可以接收number类型相加。

有一个函数叫做double,它可以接收number类型并返回它的两倍,也可以接收string类型并返回它与自身拼接的结果。代码如下:

function double(x: number): number;
function double(x: string): string;
function double(x: number | string): number | string {
  if (typeof x === 'number') {
    return x * 2;
  } else {
    return x + ', ' + x;
  }
}
let d = double(1);

ts—interface

1、定义: 为了定义对象类型。例如

interface Person {
    name: String,
    age: Number
}
let tom: Person = {
  name: 'Tom',
  age: 25
};

2、特点:

  • 可选属性:接口里的属性不全都是必需的。带有可选属性的接口与普通的接口定义差不多,只是在可选属性名字定义的后面加一个?符号。
  • 可读属性:readonly
  • 可以描述自定义属性
  • 可以描述函数类型:
interface AddFunc {
  (num1: number, num2: number): number;
}

总结:接口非常灵活。

image.png

ts_类

1、写法:与js差不多,增加了一些定义。

2、特点:

  • 增加了private, public, protected修饰符
  • 抽象类:1、只能被继承,不能被实例化。2、作为基类,抽象方法必须被子类实现。
  • interface约束类,使用implements关键字

image.png

三、ts进阶

高级类型

1、联合类型与交叉类型
  • 联合类型:联合类型通过 | 符号连接多个类型从而生成新的类型。它主要是取多个类型的交集,即多个类型共有的类型才是联合类型最终的类型。联合类型可以是多个类型其中一个,可做选择。

  • 交叉类型:交叉类型由一组有序的成员类型构成,交叉类型表示类型同时为多个类型,等同于运算符 &&,类似于数学运算中的乘法。交叉类型也是通过交叉类型字面量来定义的。 image.png

2、类型断言

类型断言的主要作用是在你比 TypeScript 更清楚某个值的类型的情况下,手动指定一个值的类型。这样可以避免 TypeScript 编译器报错,同时也可以让你更好地利用 TypeScript 的类型系统。

类型断言是 TypeScript 中的一个概念,它允许你手动指定一个值的类型。类型断言有两种形式。一种是“尖括号”语法:

let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;

另一种是 as 语法:

let someValue: any = "this is a string";
let strLength: number = (someValue as string).length;

两种形式是等价的。需要注意的是,在使用 JSX 时,只有 as 语法断言是被允许的。

3、类型别名(type vs interface)

二者都是给类型起别名。 相同点:都可以定义对象或函数,都允许继承

不同点:

  • interface是用来定义对象,type用来定义别名方便使用。
  • type可以定义基本类型,interface不行。
  • interface可以合并重复声明,type不行

总结:interface是一个接口的概念,用来描述对象。type别名的概念,用来对各个别名定义。

image.png

ts—泛型-什么时候需要泛型?

1、泛型是 TypeScript 中的一个重要概念,它允许你在定义函数、接口、类时不预先指定具体的类型,而是在使用时指定类型。泛型可以用来创建可重用的组件,一个组件可以支持多种类型的数据。这样用户就可以以自己的数据类型来使用组件。

2、泛型的语法是使用尖括号 <> 来包裹类型变量,一般可以用 T 来表示或者其他任何表示。T 相当于一个占位符或者变量,在使用时把定义的类型像参数传入。泛型可以在定义函数、接口或类时不预先指定类型,而是使用时指定类型。

3、使用时有两种方法指定类型: 当使用泛型时,有两种方法可以指定类型:

  • 显式指定类型:在调用泛型函数或实例化泛型类时,可以在尖括号 <> 中显式指定类型。例如:
function identity<T>(arg: T): T {
  return arg
 }

let output = identity<string>("myString");
  • 类型推断:在调用泛型函数或实例化泛型类时,如果不显式指定类型,TypeScript 编译器会根据传入的参数自动推断出类型。例如:
function identity<T>(arg: T): T {
  return arg
 }
let output = identity("myString");

在这个例子中,虽然我们没有显式指定类型,但 TypeScript 编译器会根据传入的参数 "myString" 推断出 T 的类型为 string

4、泛型的作用:临时占位,通过传过来的类型进行临时推导。

如何使用泛型来定义一个函数:

function identity<T>(arg: T): T {
  return arg;
}

在这个例子中,我们定义了一个名为 identity 的函数,它接收一个类型为 T 的参数 arg 并返回一个类型为 T 的值。当我们调用这个函数时,可以指定 T 的具体类型:

let output = identity<string>("myString");

ts—泛型-基础操作符

在 TypeScript 中,有一些基础操作符可以用来操作泛型类型:

  • typeoftypeof 操作符可以用来获取一个变量的类型。例如:
let s = "hello";
type TypeOfS = typeof s; // TypeOfS 的类型为 string
  • keyofkeyof 操作符可以用来获取一个对象类型的所有键。例如:
interface Person {
  name: string;
  age: number;
}

type PersonKeys = keyof Person; // PersonKeys 的类型为 "name" | "age"
  • inin 操作符可以用来遍历枚举类型。例如:
type Keys = "a" | "b" | "c";
type Obj = { [p in Keys]: any }; // Obj 的类型为 { a: any, b: any, c: any }
  • T[K]:索引访问操作符 T[K] 可以用来获取对象类型 T 的属性 K 的类型。例如:
interface Person {
  name: string;
  age: number;
}

type NameType = Person["name"]; // NameType 的类型为 string
  • extends:条件类型中的 extends 关键字可以用来判断一个类型是否能够赋值给另一个类型。例如:
interface Animal {
  name: string;
}

interface Cat extends Animal {
  meow(): void;
}

type IsCat<T> = T extends Cat ? true : false;

type A = IsCat<Cat>; // A 的类型为 true
type B = IsCat<Animal>; // B 的类型为 false

image.png

ts—泛型-常用工具类型

image.png

四、ts实战

声明文件

在 TypeScript 中,当我们使用第三方库时,通常需要提供一个声明文件来描述这个库的类型信息。声明文件通常以 .d.ts 为后缀,它包含了第三方库的类型定义。

  • declaredeclare 关键字用来定义一个全局变量。例如:
declare var $: any;
  • .d.ts:声明文件通常以 .d.ts 为后缀,它包含了第三方库的类型定义。例如:
// jquery.d.ts
declare var $: any;
  • @types@types 是一个 npm 包,它包含了许多第三方库的声明文件。你可以通过安装对应的 @types 包来获取第三方库的类型定义。例如:
npm install @types/jquery
  • tsconfig.json:在 tsconfig.json 文件中,你可以配置 TypeScript 编译器的相关选项,包括声明文件的相关配置。例如:
{
  "compilerOptions": {
    "typeRoots": ["./node_modules/@types"]
  }
}

泛型约束后端接口类型

image.png

五、课程总结

image.png