TypeScript学习2

154 阅读6分钟

代码示例传送门

TypeScript函数详解

函数类型

函数类型两种方式:作为参数 或 定义常量来编写函数体

1. 函数作为参数

// 1. 函数作为参数
// 没有写fn的类型注解则是 any类型
// 函数类型: () => void
type FunType = () => void
function bar(fn: FunType) { }
​
bar(foo)

2. 定义常量

// 2. 定义常量,编写函数类型
// 如果函数需要参数,在类型中同样要注明参数个数与类型
// 返回值值同样可以注明,但void可以返回任意类型
// 但是形参命名不固定,在实例的时候可以自定参数名
type AddFunType = (num1: number, num2: number) => number
const add: AddFunType = (a: number, b: number) => {
  return a + b
}
​
// 示例
function calc(n1: number, n2: number, fn: (num1: number, num2: number) => number) {
  return fn(n1, n2)
}
​
const result = calc(10, 20, (a, b) => a +b)
console.log(result); // 30

参数的可选类型

当参数个数限定时,必须传入相同个数才能调用函数;使用可选类型的话,可以根据情况传入参数个数。

// 可选类型是必须写在必选类型的后面
function sum(num1: number, ann?: number) {
  return num1 + ann
}
​
sum(10, 20)
sum(1)

参数默认值

参数默认值和可选类似,能够指定参数的默认值,当没传入某个值时可以使用默认值。

// 属于 js的特性
function foo(x: number , y: number = 20) {
  return x + y
}
​
console.log(foo(10)); // 30console.log(foo(10, 30)); // 40

剩余参数

使用剩余参数,可以随意选择想传入指定类型的参数的个数

function sum(...nums: number[]){
  console.log(nums);
  return nums.reduce((pre, cur) => pre += cur, 0)
}
​
console.log(sum(1, 2, 4, 5,6));  // 18

函数的重载

1. 使用联合类型,让参数类型灵活

// 重载一:
/**
 * 联合类型缺点:
 * 1. 进行很多的逻辑判断(类型缩小)
 * 2. 返回值的类型不能确定
 */
function add(a1: string | number, a2: string | number) {
  // return a1 + a2;  联合类型无法相加
  if(typeof a1 === 'number' && typeof a2 === "number"){
    return a1 + a2
  }
}

2. 函数名相同,让参数类型或个数不同

// 重载二:(推荐)
// 函数名称相同,但是参数不同的几个函数
function sum(num1: number, num2: number):number // 无函数体
function sum(num1: string, num2: string):stringfunction sum(num1: any, num2: any): any {
  return num1 + num2
}
​
const result = sum(10, 20)
const res = sum("hello", "world")
console.log(result);
console.log(res);
​
// 匹配不到对应的重载函数,函数将不被调用
// 如果没有重载函数,则匹配any,可以进行调用
// sum({name: "coder"}, {age: 18})

重载练习

function getLength(args: string | any[]) {
  return args.length
}
​
console.log(getLength("Cdsf"));
console.log(getLength([1, 3, 67]));
​
// 函数重载
function getLen(args: string):number
function getLen(args: any[]):numberfunction getLen(args: any):number {
  return args.length
}
​
console.log(getLen("无滑石粉"));
console.log(getLen([1, 3, 67]));

TypeScript类的使用

1.类的定义

类里面的属性如果没有构造函数的话,需要给定初始值;当存在构造函数给值的话,则不需要初始化值。

// 定义的时候初始化值,或者使用构造函数初始化值
// 属性是需要存值的
class Person {
  name: string = ""
  age: numberconstructor(name: string, age: number) {
    this.name = name
    this.age = age
  }
​
  eating() {
    console.log(this.name + " is eating");
  }
}
​
const p = new Person("tom", 18)
p.eating()

2.类的继承

子类继承父类,可以使用父类的属性,但是需要在构造函数里先调用父类构造函数实例化出才能够拿到父类的属性。 —— super()函数

class Person {
  name: string = ""
  age: number = 0constructor(name: string, age: number) {
    this.name = name
    this.age = age
  }
​
  eating() {
    console.log(this.name + " is eating");
  }
}
​
class Student extends Person{
  sno: numberconstructor(name: string, age: number, sno: number) {
    // super调用父类的构造方法
    // 必须写在最前面,父类实例后才能拿过来
    super(name, age)
    this.sno = sno
  }
​
  studying() {
    console.log("studying")
  }
​
  // 重写父类的方法,一个同名的函数
  eating(): void {
    // 调用父类的方法
      super.eating()
      console.log("student ee");
  }
}
​
class Teacher extends Person{
  subject: string = ""teaching() {
    console.log("teaching");
  }
}
​
​
​
const t = new Teacher("Axiu", 22)
const stu = new Student("jack", 18, 2022)
t.eating()
stu.eating()

3.类的多态

类只能继承一个,继承类后也同样属于继承类的类型

class Animal {
  action() {
    console.log("action");
  }
}
​
class Fish extends Animal {
  action () {
    console.log("swimming");
    
  }
}
​
class Dog extends Animal{
  action() {
    console.log("Running");
    
  }
}
​
class Bird extends Animal {
  action(): void {
    console.log("flying");
  }
}
​
// animals:
// 父类引用指向子类对象
function makeActions(animals: Animal[]) {
  // 执行重写之后的代码
  animals.forEach(animal => animal.action())
}
​
makeActions([new Dog(), new Fish(), new Bird()])

4.成员修饰符

成员包括:函数和属性

  • public公有: 默认不写的话,都是public,在任何地方都能够访问到

  • private私有: 只能在类的内部访问,或者是通过方法内部调用

  • protected: 受保护的属性,只能在类或者子类里面调用

  • readonly: 只读属性

    1. 可以在构造函数中赋值,但后续不能更改
    2. 属性如果是个对象,则属性可以更改,但是对象本身地址无法更改
class Person {
  // 默认不写的话,都是public
  // 在任何地方都能够使用实例访问到
  public name: string = ""// 只能在类的内部访问
  // 或者调用类方法
  private age: number = 0
  setAge(newAge: number) {
    this.age = newAge
  }
  getAge() {
    return this.age
  }
​
  // 受保护的属性,只能在类或者子类里面访问 
  protected height: number = 1.8// 只读属性
  // 1.可以在构造函数中赋值,但是后续不可更改
  // 2. 属性如果是个对象,则属性可以修改,但是对象无法更改
  readonly sex: string
  constructor(sex: string = "male") {
    this.sex = sex
  }
  
​
  // 修饰函数
  public walk() {
    console.log("walking");
  }
​
  protected speak() {}
  private sleep() {}
​
​
  // 静态属性
  // 修饰一些不变的值或函数
  static time: string = "45分钟"
  static hungry() {
    console.log("准备吃饭!");
  }
}
​
​
class Student extends Person {
  getInfo() {
    console.log(this.name);
    // console.log(this.age);
    console.log(this.getAge);
    console.log(this.height);
  }
}
​
// 通过实例对象的 . 联想只能获取能能拿的值
const p = new Person("female")
console.log(p.name);
console.log(p.getAge);
// console.log(p.height);
console.log(p.sex);
// 只读属性无法更改
// p.sex = "hha"// 静态属性或者方法通过类直接访问
const time = Person.time
console.log(time);
Person.hungry()
​
​
​
const stu = new Student()
stu.getInfo()

5.get 和 set

可以通过 get 和 set 方法,获取和修改private私有属性

class Person {
  // 习惯:私有属性以下划线开头
  private _name: string
  constructor(name: string) {
    this._name = name
  }
​
  // 访问器 setter /getter
  set name(newName:string) {
    this._name = newName
  }
  get name() {
    return this._name
  }
}
​
const p = new Person("tom")
// 访问器可以像属性一样使用
p.name = "jack"
console.log(p.name);

6.抽象类 abstract

抽象顾名思义就是只有个大概,并不是很详细;

// 抽象方法必须存在于抽象类中
abstract class Shape {
  // 抽象方法可以不写函数体
  abstract getArea(): number
}
​
// 子类如果不实现抽象方法,则必须也为抽象类
abstract class Triangle extends Shape {}

实现抽象类的方法

// 继承抽象类必须实现抽象类的抽象方法
class Rectangle extends Shape { 
  private width: number = 0
  private height: number = 0
​
  constructor(width: number, height: number){
    // 即使是抽象类,也必须先实例父类才能够继承
    super()
    this.width = width
    this.height = height
  }
​
  // 实现抽象方法
  getArea() {
    return this.width * this.height
  }
}
​
class Circle extends Shape {
  private radius: number = 0
​
  constructor(radius: number) {
    super()
    this.radius = radius
  }
  
  getArea() {
    return  Math.PI * (this.radius ** 2)
  }
}

写一个函数,要存在着getArea方法才能够使用;这时使用抽象方法,继承了shape类的类,定拥有该方法

// 如果不限定参数类型,则无法知道参数是否存在 getArea方法
// 父类引用到子类
function getAreaSize(shape: Shape) {
  return shape.getArea()
}
​
const rect = new Rectangle(10, 20)
const circle = new Circle(6)
console.log(getAreaSize(rect));
console.log(getAreaSize(circle));

7.类的类型

和其他类型一样,类拥有的属性,实例出来的对象也有用有

class Person {
  name: string = "tom"
}
​
const p = new Person()
​
// Person内部拥有什么属性,实例对象同样也需要拥有对应属性
const person: Person = {
  name: "jack"
}