前端知识框架 前端知识框架
首页
基础
框架
插件
Node
地图
更多
前端须知
  • 分类
  • 标签
  • 归档

BestIdea

首页
基础
框架
插件
Node
地图
更多
前端须知
  • 分类
  • 标签
  • 归档
  • 国产机环境浏览器兼容问题收集(持续收集)
  • canvas电子画板,适用于H5版本,组件产出为blob类型的文件流
  • Css3 filter(滤镜) 属性
  • css选择器
  • http缓存
  • less语法
  • New date()浏览器时间兼容性
  • rem自动适应性布局方案
  • 浏览器缓存机制
  • 屏幕适配
  • 前端基础方法汇总
  • 图片转码下载方式(解决浏览器下载图片时直接打开图片问题)
  • CSS命名规范
  • 大屏定位解决方案
  • TypeScript入门
    • 基本
      • 简单数据类型
      • 类型推论
      • 联合类型
      • 复杂数据类型
      • 接口
      • 继承
      • 类型断言
      • 声明文件
    • 进阶
      • 类型别名
      • 字符串字面量类型
      • 元祖
      • 枚举
      • 类
      • 类与接口
  • 解决有些浏览器rem不以html的font-size为基准问题
  • 解决Vue项目页面缩放问题
  • H5扫一扫功能
  • crypto前端加密
  • 基础
郝东建
2023-04-14
目录

TypeScript入门

添加了类型系统的 JavaScript,适用于任何规模的项目

# 基本

# 简单数据类型

let isDone: boolean = false;
let decLiteral: number = 6;
let hexLiteral: number = 0xf00d;
let myName: string = "Tom";
let u: undefined = undefined;
let n: null = null;

// JavaScript 没有空值(Void)的概念,在 TypeScript 中,可以用 void 表示没有任何返回值的函数:
function alertName(): void {
  alert("My name is Tom");
}

//任意值
let myFavoriteNumber: any = "seven";
myFavoriteNumber = 7;
//变量如果在声明的时候,未指定其类型,那么它会被识别为任意值类型:

let something;
something = "seven";
something = 7;

something.setName("Tom");
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 类型推论

如果没有明确的指定类型,那么 TypeScript 会依照类型推论(Type Inference)的规则推断出一个类型。

let myFavoriteNumber: string = "seven";
myFavoriteNumber = 7;

// index.ts(2,1): error TS2322: Type 'number' is not assignable to type 'string'.
1
2
3
4

# 联合类型

联合类型的变量在被赋值的时候,会根据类型推论的规则推断出一个类型

let myFavoriteNumber: string | number;
myFavoriteNumber = "seven";
myFavoriteNumber = 7;
1
2
3

# 复杂数据类型

// 最简单的方法是使用「类型 + 方括号」来表示数组:
let fibonacci: number[] = [1, 1, 2, 3, 5];
// 我们也可以使用数组泛型(Array Generic) Array<elemType> 来表示数组:
let fibonacci: Array<number> = [1, 1, 2, 3, 5];
// 一个比较常见的做法是,用 any 表示数组中允许出现任意类型:
let list: any[] = ["xcatliu", 25, { website: "http://xcatliu.com" }];
1
2
3
4
5
6
// 限制函数参数和返回值类型
function sum(x: number, y: number): number {
  return x + y;
}
// 可选参数
function buildName(firstName: string, lastName?: string) {
  if (lastName) {
    return firstName + " " + lastName;
  } else {
    return firstName;
  }
}
// 参数默认值
function buildName(firstName: string, lastName: string = "Cat") {
  return firstName + " " + lastName;
}
// 剩余参数
function push(array, ...items) {
  items.forEach(function (item) {
    array.push(item);
  });
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 接口

interface Person {
  name: string;
  age: number;
}

let tom: Person = {
  name: "Tom",
  age: 25,
};

// 可选属性
interface Person {
  name: string;
  age?: number;
}

let tom: Person = {
  name: "Tom",
};

// 任意属性

interface Person {
  name: string;
  age?: number;
  [propName: string]: any;
}

let tom: Person = {
  name: "Tom",
  gender: "male",
};

//只读
interface Person {
  readonly id: number;
  name: string;
  age?: number;
  [propName: string]: any;
}

let tom: Person = {
  id: 89757,
  name: "Tom",
  gender: "male",
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

# 继承

interface Error {
  name: string;
  code: number;
}
interface ApiError extends Error {
  code2: number;
}
1
2
3
4
5
6
7

# 类型断言

类型断言(Type Assertion)可以用来手动指定一个值的类型

  • 联合类型可以被断言为其中一个类型
  • 父类可以被断言为子类
  • 任何类型都可以被断言为 any
  • any 可以被断言为任何类型

# 声明文件

当使用第三方库时,我们需要引用它的声明文件,才能获得对应的代码补全、接口提示等功能,通常我们会把声明语句放到一个单独的文件(jQuery.d.ts)中,这就是声明文件

  • declare var 声明全局变量
  • declare function 声明全局方法
  • declare class 声明全局类
  • declare enum 声明全局枚举类型
  • declare namespace 声明(含有子属性的)全局对象
  • interface 和 type 声明全局类型
  • export 导出变量
  • export namespace 导出(含有子属性的)对象
  • export default ES6 默认导出
  • export = commonjs 导出模块
  • export as namespace UMD 库声明全局变量
  • declare global 扩展全局变量
  • declare module 扩展模块
  • /// <reference /> 三斜线指令
// src/jQuery.d.ts

declare let jQuery: (selector: string) => any;

// src/Directions.d.ts

declare enum Directions {
  Up,
  Down,
  Left,
  Right,
}
1
2
3
4
5
6
7
8
9
10
11
12

# 进阶

# 类型别名

类型别名用来给一个类型起个新名字。

// 首先说下可以用接口重写类型别名
type People = {
  name: string;
  age: number;
};

// 可以重写为下面这个接口

interface People {
  name: string;
  age: number;
}

// 现在二者完全一样,任何使用类型别名 People 的地方都可以使用接口 People
// 第一个区别
// 类型别名右边可以是多种类型,包括类型、|、&等
type A = number;
type B = A | string;

// 接口只能为类型
interface A {
  name: string;
}
// 第二个区别
// 扩展接口时会检查是否可被赋值
interface A {
  func(x: number): number;
}
interface B extends A {
  func(x: string): string;
}

// 如果 B 继承 A 会报错
// 而如果把接口写成类型别名,extends 换成 & 则不会报错,别名会重载这个 func
// 第三个区别
// 同一作用域下的多个同名接口会自动合并,而类型别名则会报错,这个就是声明合并

interface People {
  name: string;
}

interface People {
  age: number;
}

// People在同一作用下会合并如下
interface People {
  name: string;
  age: number;
}
// 如果将 interface 换成 type 则会报错
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

# 字符串字面量类型

type EventNames = "click" | "scroll" | "mousemove";
function handleEvent(ele: Element, event: EventNames) {
  // do something
}

handleEvent(document.getElementById("hello"), "scroll"); // 没问题
handleEvent(document.getElementById("world"), "dblclick"); // 报错,event 不能为 'dblclick'
1
2
3
4
5
6
7

# 元祖

数组合并了相同类型的对象,而元组(Tuple)合并了不同类型的对象。

let tom: [string, number] = ["Tom", 25];
let tom: [string, number];
tom[0] = "Tom";
tom[1] = 25;

tom[0].slice(1);
tom[1].toFixed(2);

// 当添加越界的元素时,它的类型会被限制为元组中每个类型的联合类型:
let tom: [string, number];
tom = ["Tom", 25];
tom.push("male");
tom.push(true);

// Argument of type 'true' is not assignable to parameter of type 'string | number'.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 枚举

枚举(Enum)类型用于取值被限定在一定范围内的场景

enum Days {
  Sun,
  Mon,
  Tue,
  Wed,
  Thu,
  Fri,
  Sat,
}
1
2
3
4
5
6
7
8
9

# 类

JavaScript 通过构造函数实现类的概念,通过原型链实现继承。而在 ES6 中,我们终于迎来了 class

# ES 中的用法

class Animal {
  public name;
  constructor(name) {
    this.name = name;
  }
  sayHi() {
    return `My name is ${this.name}`;
  }
}

let a = new Animal("Jack");
console.log(a.sayHi()); // My name is Jack

// 使用 extends 关键字实现继承,子类中使用 super 关键字来调用父类的构造函数和方法。
class Cat extends Animal {
  constructor(name) {
    super(name); // 调用父类的 constructor(name)
    console.log(this.name);
  }
  sayHi() {
    return "Meow, " + super.sayHi(); // 调用父类的 sayHi()
  }
}

let c = new Cat("Tom"); // Tom
console.log(c.sayHi()); // Meow, My name is Tom

// 使用 getter 和 setter 可以改变属性的赋值和读取行为:
class Animal {
  constructor(name) {
    this.name = name;
  }
  get name() {
    return "Jack";
  }
  set name(value) {
    console.log("setter: " + value);
  }
}

let a = new Animal("Kitty"); // setter: Kitty
a.name = "Tom"; // setter: Tom
console.log(a.name); // Jack

// 使用 static 修饰符修饰的方法称为静态方法,它们不需要实例化,而是直接通过类来调用

class Animal {
  static isAnimal(a) {
    return a instanceof Animal;
  }
}

let a = new Animal("Jack");
Animal.isAnimal(a); // true
a.isAnimal(a); // TypeError: a.isAnimal is not a function

// ES6 中实例的属性只能通过构造函数中的 this.xxx 来定义,ES7 提案中可以直接在类里面定义:
class Animal {
  name = "Jack";

  constructor() {
    // ...
  }
}

let a = new Animal();
console.log(a.name); // Jack
// ES7 提案中,可以使用 static 定义一个静态属性:
class Animal {
  static num = 42;

  constructor() {
    // ...
  }
}

console.log(Animal.num); // 42
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77

# TypeScript 中的用法

TypeScript 可以使用三种访问修饰符(Access Modifiers),分别是 public、private 和 protected。

  • public 修饰的属性或方法是公有的,可以在任何地方被访问到,默认所有的属性和方法都是 public 的
  • private 修饰的属性或方法是私有的,不能在声明它的类的外部访问
  • protected 修饰的属性或方法是受保护的,它和 private 类似,区别是它在子类中也是允许被访问的
class Animal {
  public name;
  public constructor(name) {
    this.name = name;
  }
}

let a = new Animal("Jack");
console.log(a.name); // Jack
a.name = "Tom";
console.log(a.name); // Tom

class Animal {
  private name;
  public constructor(name) {
    this.name = name;
  }
}

class Cat extends Animal {
  constructor(name) {
    super(name);
    console.log(this.name);
  }
}

// index.ts(11,17): error TS2341: Property 'name' is private and only accessible within class 'Animal'

class Animal {
  protected name;
  public constructor(name) {
    this.name = name;
  }
}

class Cat extends Animal {
  constructor(name) {
    super(name);
    console.log(this.name);
  }
}

// 修饰符和readonly还可以使用在构造函数参数中,等同于类中定义该属性同时给该属性赋值,使代码更简洁。

class Animal {
  // public name: string;
  public constructor(public name) {
    // this.name = name;
  }
}

class Animal {
  // public readonly name;
  public constructor(public readonly name) {
    // this.name = name;
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57

abstract 用于定义抽象类和其中的抽象方法。

abstract class Animal {
  public name;
  public constructor(name) {
    this.name = name;
  }
  public abstract sayHi();
}

let a = new Animal("Jack");

// index.ts(9,11): error TS2511: Cannot create an instance of the abstract class 'Animal'.

// 抽象类中的抽象方法必须被子类实现:

abstract class Animal {
  public name;
  public constructor(name) {
    this.name = name;
  }
  public abstract sayHi();
}

class Cat extends Animal {
  public sayHi() {
    console.log(`Meow, My name is ${this.name}`);
  }
}

let cat = new Cat("Tom");
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# 类与接口

# 类实现接口

上次更新: 2024/01/18, 10:44:15
大屏定位解决方案
解决有些浏览器rem不以html的font-size为基准问题

← 大屏定位解决方案 解决有些浏览器rem不以html的font-size为基准问题→

最近更新
01
webpack打包替换类名命名空间
05-01
02
Vite常用配置
02-26
03
crypto前端加密
01-18
更多文章>
Theme by Vdoing | Copyright © 2022-2024
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式