廖亚军的个人博客

Logo

苟日新,日日新,又日新

Typescript 简介

为何需要 Typescript

1. 今非昔比的 Javascript

编译 Typescript

浏览器不能直接运行 TypeScript 代码,需要编译为 JavaScript 再交由浏览器解析器执行

1. 命令行编译(不常用)

2. 自动化编译

类型声明

类型推断

类型总览

JavaScript 中的数据类型

TypeScript 中的数据类型

注意

常用类型

1. any: 任意类型

2. unknown: 未知类型

3. never: 不存在的类型

4. void: 空(无返回值方法)

5. object

声明数组类型

let arr1: string[]
let arr2: Array<number>
arr1 = ['a', 'b', 'c']
arr2 = [1, 2, 3]

声明对象类型

声明函数类型

// 这个声明函数名为 count 的函数
// 只接受两个 number 的参数,返回一个 number 的结果
let count: (a: number, b: number) => number;
count = function (a, b) {
  return a + b;
};

6. tuple(元组)

7. enum(枚举)

数字枚举

字符串枚举

常量枚举

8. type

9. 一个特殊情况

// 显式返回类型注解
// 严格模式,严格要求返回值为空
function demo(): void {
    // return;
    return undefined;
}
// 上下文类型推断
// 宽松模式,不会严格要求返回值为空,但是返回值无法使用
type demo = () => void
const demo1: demo = () => {
  return 'demo1'
}

10. 复习类相关知识

class Person {
  // 属性声明
  name: string
  age: number
  // 构造器
  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
  // 方法
  speak() {
    console.log(`我的名字是 ${this.name},我今年 ${this.age} 岁。`);
  }
}

class Student extends Person {
  grade: string
  // 构造器
  // 如果没有新增属性,则可以省略构造器,直接使用父类的构造器
  // 如果子类中有构造器,则必须调用 super() 来调用父类的构造器
  constructor(name: string, age: number, grade: string){
    super(name, age)
    this.grade = grade
  }
  // 重写父类的方法
  override speak() {
    console.log(`我是学生,我的名字是 ${this.name},我今年 ${this.age} 岁,我在读 ${this.grade} 年级。`)
  }
  // 子类新增的方法
  study() {
    console.log(`${ this.name }正在努力学习中...`)
  }
}
const student = new Student('小明', 20, '大三')
student.speak()
student.study()

11. 属性修饰符

12. 抽象类(abstract)

class StandardPackage extends Package { constructor(weight: number, public unitPrice: number) { super(weight) } calculate(): number { return this.weight * this.unitPrice } } const standardPackage = new StandardPackage(10, 5) standardPackage.print()

- 使用抽象类的场景
  - 定义通用接口
  - 提供基础实现
  - 确保关键实现
  - 共享代码和逻辑

### 13. interface

- interface 是一种定义结构的方式,主要作用是为:类、对象、函数等规定一种契约,这样可以确保代码的一致性和类型安全,但是 interface 只能定义格式,不能包含任何实现
- 定义类结构
  ```typescript
  interface PersonInterface {
      name: string;
      age: number;
      speak(n: number): void;
  }
  class Person implements PersonInterface {
    constructor(public name: string, public age: number) {}
    speak(n: number): void {
      for (let i = 0; i < n; i++) {
        console.log(`你好,我是${this.name},今年${this.age}岁。`);
      }
    }
  }
  const person = new Person("张三", 30);
  person.speak(3);

14. 一些相似概念的区别

interface 和 type 区别

interface 和抽象类区别

泛型

类型声明文件

装饰器

简介

类装饰器

/**
 * Function 类型的范围非常广泛,包括普通函数、箭头函数、构造函数等。为了更准确地描述构造函数类型,我们可以使用一个特殊的类型别名来表示它。
 * new (...args: any[]) => {}
 * new 表示该类型是一个构造函数类型,可以使用 new 操作符调用
 * ...args 表示构造器可以接受任意数量的参数
 * any[] 表示构造器可以接受任意类型的参数
 * {} 表示返回类型是对象,非 null、非 undefined 的值
 */
type Constructor = new (...args: any[]) => {};
interface Person {
  getTime(): string;
}
function LogTime<T extends Constructor>(target: T) {
  return class extends target {
    createTime: Date;
    constructor(...args: any[]) {
      super(...args);
      this.createTime = new Date();
    }
    getTime() {
      return `该对象的创建时间是: ${this.createTime}`;
    }
  };
}
// @LogTime 等价于 LogTime(Person)
@LogTime
class Person {
  name: string;
  age: number;
  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
  speak() {
    console.log(`我的名字是${this.name},今年${this.age}岁了`);
  }
}
const p1 = new Person('张三', 20);
console.log(p1);
console.log(p1.getTime());

装饰器工厂

@LogInfo(3) class Person { constructor( public name: string, public age: number ) {} } const p1 = new Person(‘张三’, 20); p1.introduce();


### 装饰器组合

- 装饰器可以组合使用,顺序是,先从上到下执行所有的装饰器工厂,依次获取到装饰器,再从下到上执行所有的装饰器
```typescript
function test1(target: Function) {
  console.log('test1')
}
function test2() {
  console.log('test2工厂')
  return function (target: Function) {
    console.log('test2')
  }
}
function test3() {
  console.log('test3工厂')
  return function (target: Function) {
    console.log('test3')
  }
}
function test4(target: Function) {
  console.log('test4')
}

@test1
@test2()
@test3()
@test4
class Person{}
/**
 * 输出结果:
 * test2工厂
 * test3工厂
 * test4
 * test3
 * test2
 * test1
 */

属性装饰器

const p1 = new Person(‘张三’, 18) const p2 = new Person(‘李四’, 20) p1.age = 19 p2.age = 21 console.log(p1.age) // 输出: 19 console.log(p2.age) // 输出: 21

 
### 方法装饰器

- 装饰器装饰方法时,会得到三个参数,target、方法名称(propertyKey)和方法的描述对象(descriptor)
- target 对于静态方法来说值是类,对于实例方法来说值是原型对象
- descriptor 方法的描述对象,其中的 value 属性是被装饰的方法
```typescript
function Logger(target: object, propertyKey: string, descriptor: PropertyDescriptor) {
  const original = descriptor.value;
  descriptor.value = function (...args: any[]) {
    console.log(`调用了${propertyKey}方法,参数是:${args.join(', ')}`);
    return original.call(this, ...args);
  };
}
class Person {
  constructor(
    public name: string,
    public age: number
  ) {}
  @Logger speak(str: string) {
    console.log(`我的名字是${this.name},今年${this.age}岁了${str}`);
  }
  static isAdult(age: number): boolean {
    return age >= 18;
  }
}
const person = new Person('张三', 20);
person.speak(',很高兴认识你!');

访问器装饰器

参数装饰器