美文网首页
03-TypeScript-泛型和类

03-TypeScript-泛型和类

作者: 低头看云 | 来源:发表于2020-10-01 15:50 被阅读0次

泛型

  • 提高代码的灵活性和可重用性
 // 需求: 定义一个创建数组的方法, 可以创建出指定长度的数组, 并且可以用任意指定的内容填充这个数组

  let getArray = (value: number, len: number = 5): number[] => {
    return new Array(len).fill(value)
  }
  let r1 = getArray(5, 6)
  console.log('r1', r1)

  // 使用泛型
  let getArray1 = <T>(value: T, len: number = 5): T[] => {
    return new Array(len).fill(value)
  }

  let r2 = getArray1(2)
  console.log('r2', r2) //  自动推导出 r2的类型是number[]
  
  
  let s1 = r2.reduce((acc, cur, index) => {
    return acc + cur
  }, '')
  console.log('s1', s1)

泛型的约束

  • 默认情况下, 可以指定泛型类型为任意类型
  • 但是有些情况下, 需要指定类型需要满足某些条件才能指定

interface LenInterface {
    length: number
  }

  let getArray2 = <T extends LenInterface>(value: T, len: number = 5): T[] => {
    return new Array(len).fill(value)
  }

  // let arr = getArray2(44)  // 报错  这个泛型函数被定义了约束,因此它不再是适用于任意类型:
  // let arr = getArray2('sssdfd') // 可以
  // 参数中要包含 length 这个属性
  let arr = getArray2({ length: 22, value: '33' })
  console.log('arr', arr)
  • 在泛型约束中使用类型参数
  // 需求:定义一个函数用于根据指定的key获取对象的value
  let getProps = <T, K extends keyof T>(obj: T, key: K): any => {
    return obj[key]
  }

  let obj = {
    a: '1',
    b: '2',
  }

  let res = getProps(obj, 'b')
  console.log('res', res)
}

  • 定义个person类
 class Person {
    name: string
    age: number
    constructor(name: string, age: number) {
      this.name = name
      this.age = age
    }
    say(): void {
      console.log(`我是名字叫${this.name},年龄是${this.age}`)
    }

    // 静态属性
    static food: string = '泡面'
    // 静态方法
    static eat(): void {
      console.log(`我在吃${this.food}`)
    }
    // 注意:  静态属性和静态方法都是通过 类名.静态方法/ 类名.静态属性 来访问
  }

  let p1 = new Person('css', 18)
  p1.say()
  Person.eat()

  Person.food = '火腿'
  • 类的继承
  // 类的继承
  class Student extends Person {
    book?: string
    constructor(name: string, age: number, book?: string) {
      super(name, age)
      this.book = book
    }
    say(): void {
      console.log(`我是重写之后的say-${this.name} - ${this.age} - ${this.book}`)
    }

    static eat(): void {
      console.log(`我是重写之后的eat-${this.food}`)
    }
  }

  let stu = new Student('zs', 18, 'js')
  stu.say()
  Student.food = '冰淇淋'
  Student.eat()

类的属性修饰符

  • public(公开的):

    • 如果使用public来修饰属性, 那么表示这个属性是公开的
    • 可以在类的内部使用, 也可以在子类中使用, 也可以在外部使用
  • protected(受保护的) :

    • 如果使用protected来修饰属性, 那么表示这个属性是受保护的
    • 可以在类的内部使用, 也可以在子类中使用
  • private(私有的) :

    • 如果使用private来修饰属性, 那么表示这个属性是私有的
    • 可以在类的内部使用
  • readonly(只读的)

  • 简单使用

class Person {
    // 默认情况下的属性修饰符是 public
    public name: string
    protected age: number // protented 修饰表示 属性是受保护的  只能在类的内部和子类中使用
    private gender: string // private 修饰属性是表示只能在类的内部使用
    constructor(name: string, age: number, gender: string) {
      this.name = name
      this.age = age
      this.gender = gender
    }
    say(): void {
      console.log(`我是名字叫${this.name},年龄是${this.age},性别${this.gender}`)
    }

    // 静态属性
    static food: string = '泡面'
    // 静态方法
    static eat(): void {
      console.log(`我在吃${this.food}`)
    }
    // 注意:  静态属性和静态方法都是通过 类名.静态方法/ 类名.静态属性 来访问
  }
  
  // stuedent继承 Person
  class Student extends Person {
    constructor(name: string, age: number, gender: string) {
      super(name, age, gender)
    }
    say(): void {
      // 属性“gender”为私有属性,只能在类“Person”中访问。
      console.log(`继承---我是名字叫${this.name},年龄是${this.age}`)
    }
  }

  let p2 = new Person('css', 14, '男')
  let stu2 = new Student('ww', 123, 'ss')
  stu2.say()

类方法的修饰符

  • public :

    • 如果使用public来修饰方法, 那么表示这个方法是公开的
    • 可以在类的内部使用, 也可以在子类中使用, 也可以在外部使用
  • protected :

    • 如果使用protected来修饰方法, 那么表示这个方法是受保护的
    • 可以在类的内部使用, 也可以在子类中使用
  • 注意点

    • protected 可以修饰constructor{}
    • 这样可以用户只能从子类创建对象 而不能从基类中创建对象
  • private

    • 如果使用private来修饰方法, 那么表示这个方法是私有的
    • 可以在类的内部使用
  • 示例

class Person1 {
    // 默认情况下的属性修饰符是 public
    public name: string
    protected age: number
    private gender: string
    constructor(name: string, age: number, gender: string) {
      this.name = name
      this.age = age
      this.gender = gender
    }
    public say(): void {
      console.log(`我是名字叫${this.name},年龄是${this.age},性别${this.gender}`)
    }

    protected sayAge(): void {
      console.log('age', this.age)
    }

    protected sayGender(): void {
      console.log('gender', this.gender)
    }

    // 静态属性
    static food: string = '泡面'
    // 静态方法
    static eat(): void {
      console.log(`我在吃${this.food}`)
    }
    // 注意:  静态属性和静态方法都是通过 类名.静态方法/ 类名.静态属性 来访问
  }

  let p3 = new Person1('react', 14, '男')
  // 'sayGender' is protected and only accessible within class 'Person1' and its subclasses.
  // p3.sayGender()

类的可选属性

// 类的可选属性
  class Person2 {
    // 在ts中定义了实例属性 那么就必须在构造函数中使用, 否则会报错
    public name: string
    protected age?: number // 可选属性
    private gender?: string
    constructor(name: string, age?: number, gender?: string) {
      this.name = name
      this.age = age
      this.gender = gender
    }
  }

参数属性

  • 一句话搞定实例属性的接收和定义
  class Person3 {
    constructor(public name: string, public age: number) {
      this.name = name
      this.age = age
    }
  }

  let pp3 = new Person3('r', 22)
  console.log('pp3', pp3)
}

类存取器

  • 通过 getters/ setters 来截取对对象成员的访问
const fullNameMaxLength = 10

  class Employee {
    private _fullName: string = ''

    get fullName(): string {
      return this._fullName
    }

    set fullName(newName: string) {
      if (newName && newName.length > fullNameMaxLength) {
        throw new Error('fullName has a max length of ' + fullNameMaxLength)
      }

      this._fullName = newName
    }
  }

  let employee = new Employee()
  employee.fullName = 'Bob'
  if (employee.fullName) {
    console.log(employee.fullName)
  }

抽象类

  • 抽象类是专门用于定义那些不希望被外界直接创建的类

  • 抽象类一般用于定义基类

  • 之前方式的创建

// 之前的方式创建
  class Base1 {
    name: string
    age: number
    protected constructor(name: string, age: number) {
      this.name = name
      this.age = age
    }
    say(): void {
      console.log(`${this.name} - ${this.age}`)
    }
  }
  class Person1 extends Base1 {
    constructor(name: string, age: number) {
      super(name, age)
    }
  }

  let p1 = new Person1('js', 21)
  p1.say()
  • 抽象类的实现
  abstract class Base {
    abstract name: string
    abstract say(): void
    eat(): void {
      console.log(this.name, '在吃东西....')
    }
  }

  class Person extends Base {
    name: string = 'css'
    say(): void {
      console.log(`我的名字是${this.name}`)
    }
  }

  let p11 = new Person()
  p11.say()
  p11.eat()

抽象类和接口的区别

  • 接口只能定义约束, 不能定义具体实现
  • 而抽象类中既可以定义约束, 又可以定义具体实现

类实现接口

interface PersonInterface {
    name: string
    say(): void
  }
  // 只要类实现了某个接口,那么就必须实现接口中所有的属性和方法
  class person implements PersonInterface {
    name: string = 'css'
    say(): void {
      console.log('hello')
    }
  }

接口继承类

  // 接口继承类
  class Person1 {
    name: string = 'css'
    age: number = 24
    say(): void {
      console.log('hello')
    }
  }
  // 一个接口继承了某个类, 那么就会继承这个类中所有的属性和方法
  // 但是只会继承属性和方法的声明, 不会继承属性和方法的实现
  interface PersonInterface1 extends Person1 {
    gender: string
  }

  class Student implements PersonInterface1 {
    name: string = 'js'
    age = 33
    gender: string = '男'
    say(): void {
      console.log('name11111111111:', this.name)
    }
  }
  let stu = new Student()
  stu.say()

  • 注意点:
    • 如果接口继承的类型包含了protected的属性和方法,
    • 那么只有这个类的之类才能实现这个接口
  class Person2 {
    name: string = 'css'
    age: number = 24
    protected say(): void {
      console.log('hello222222222222222')
    }
  }
  interface PersonInterface2 extends Person2 {
    gender: string
  }
  class Student1 extends Person2 implements PersonInterface2 {
    name: string = 'js'
    age = 33
    gender: string = '男'
    say(): void {
      console.log('name22222222222222222222:', this.name)
    }
  }

  let stu1 = new Student1()
  stu1.say()

泛型类和接口合并现象

  • 定义一个泛型类
 // 泛型类
  class Chache<T> {
    arr: T[] = []
    add(value: T): T[] {
      this.arr.push(value)
      return this.arr
    }
  }

  let chache = new Chache<number>()
  let res = chache.add(3)
  console.log('res', res)

  • 接口合并现象
  • 定义多个同名的接口时, 多个接口的内容会自动合并
interface TestInterface {
    name: string
  }

  interface TestInterface {
    age: number
  }

  class Person implements TestInterface {
    name: string = 'zs'
    age: number = 12
  }

相关文章

  • 03-TypeScript-泛型和类

    泛型 提高代码的灵活性和可重用性 泛型的约束 默认情况下, 可以指定泛型类型为任意类型 但是有些情况下, 需要指定...

  • Java 19-5.1泛型

    泛型类定义泛型类可以规定传入对象 泛型类 和泛型方法 泛型接口 如果实现类也无法确定泛型 可以在继承类中确定泛型:

  • 【泛型】通配符与嵌套

    上一篇 【泛型】泛型的作用与定义 1 泛型分类 泛型可以分成泛型类、泛型方法和泛型接口 1.1 泛型类 一个泛型类...

  • 重走安卓进阶路——泛型

    ps.原来的标题 为什么我们需要泛型? 泛型类、泛型接口和泛型方法(泛型类和泛型接口的定义与泛型方法辨析); 如何...

  • 三泛型的使用

    1.泛型类和泛型方法 (1)格式 (2)示例例如a.泛型类 b.实现方法 2.泛型接口和泛型方法 (1)格式 (2...

  • 泛型(持续更新中......)

    一、泛型类和泛型接口 1.如果定义了泛型类,实例化没有指明类的泛型,则认为此泛型类型为Object类型。2.要求:...

  • 泛型

    一、泛型类、泛型接口和泛型方法1、泛型接口的定义: 2、两种泛型类的定义:(1) (2) 3、泛型方法的定义,可以...

  • 泛型、反射和注解

    泛型可以分为:泛型类,泛型接口和泛型方法 泛型类:容器类可以算的上是最具有重用性的类之一。 先来看一下一个没有泛型...

  • kotlin--泛型

    kotlin作为一种高级语言,也提供了泛型,它的泛型比Java更为灵活 一、泛型类 1.定义泛型类 定义泛型类和J...

  • Scala 中的特殊符号 ---- 泛型边界 <: >:

    泛型的边界 <: 和 >: 符号 <:和>:都是用来表示泛型的边界,如:有以下类声明: 声明拥有泛型的类: 说明:...

网友评论

      本文标题:03-TypeScript-泛型和类

      本文链接:https://www.haomeiwen.com/subject/cwruuktx.html