ts总结 之 类

本文详细介绍了 TypeScript 中的类、构造函数、继承、抽象类、接口、属性封装(public、private、protected、get、set)以及泛型的用法,通过实例展示了如何在 TypeScript 中创建和使用这些概念,帮助读者深入理解 TypeScript 的面向对象编程特性。

其他内容
ts中的类型
编译选项
webpack打包

1.类的简介

使用class关键字
对象中主要包含的两个部分:属性、方法

class Person {
  /**
   * 直接定义的属性是实例属性。需要通过对象的实例去访问:
   *  const per = new Person()
   *  Person.age
   * 
   * readonly 代表只读属性
   * static readonly 代表静态只读属性
   */
  // 定义实例属性
  name: string = '孙悟空'
  // 定义类属性(静态属性):不需要创建对象就能使用的静态属性
  static age: number = 18

  // 定义方法
  /**
   * 以 static 为类方法
   * 没有的化直接通过实例调用
   */
  sayHello() {
    console.log('Hello 大家好')
  }
}

const per = new Person()
// console.log(per)
// console.log(per.name)
// console.log(Person.age)

// per.name = '荔枝'
// console.log(per.name)
per.sayHello()

2.构造函数 constructor

constructor中的this谁创建就属于谁

(function () {
  class Dog {
    name: string
    age: number
    // 构造函数会在对象创建时调用
    constructor(name: string, age: number) {
      // 在实例方法中,this代表当前的实例(对象)
      // 谁创建,this属于谁
      // 可以通过this给新建对象中添加属性
      // console.log('构造函数执行了', this)
      this.name = name
      this.age = age
    }
    bark() {
      console.log(this.name)
    }
  }
  const dog = new Dog('小黑', 4)
  const dog1 = new Dog('小白', 2)
  // console.log(dog)
  // console.log(dog1)
  dog.bark()
  dog1.bark()
})()

3.继承 extends

  • 使用继承后,子类将拥有父类所有属性和方法, 通过继承可以将多个类中共有的代码写在一个父类中, 这样只需要写一次就可以同时拥有父类中的属性和方法
  • 如果想要添加父类没有的属性或方法,直接添加即可;如果在子类中添加了父类同样的方法,则子类会覆盖掉父类的方法, 这称之为方法的重写
(function () {
  // Animal被称为父类,Dog与Cat称为子类
  class Animal {
    name: string
    age: number
    constructor(name: string, age: number) {
      this.name = name
      this.age = age
    }
    sayHello() {
      console.log('动物在叫')
    }
  }
  // 定义一个Dog类,继承Animal类
  class Dog extends Animal {
    sex: string
    constructor(name: string, age: number, sex: string) {
      // 如果在子类中写了构造函数,在子类的构造函数中必须对父类的构造函数进行调用
      super(name, age)  // 调用父类的构造函数
      this.sex = sex
    }
    run() {
      console.log(`${this.name}在跑`)
    }
    sayHello() {
      console.log('汪汪汪')
    }
  }
  // 定义一个Cat类,继承Animal类
  class Cat extends Animal {
    sayHello() {
      // 在类的方法时, super表示当前类的父类
      super.sayHello()
    }
  }
  const dog = new Dog('旺财', 5, '公')
  console.log(dog)
  dog.sayHello()
  dog.run()
  const cat = new Cat('咪咪', 3)
  cat.sayHello()
})()

4.抽象类 abstract

创建抽象类的目的:用来被别人继承。抽象类本身不能被用来创建对象,抽象类中能添加抽象方法

(function () {
  abstract class Animal {
    name: string
    age: number
    constructor(name: string, age: number) {
      this.name = name
      this.age = age
    }
    /***
     * 定义一个抽象方法
     * 抽象方法使用abstract开头,没有方法体
     * 抽象方法只能定义在抽象类中,子类必须对抽象方法重写
     */
    abstract sayHello(): void;
  }
  class Dog extends Animal {
    sayHello() {
      console.log('汪汪汪')
    }
  }
  class Cat extends Animal {
    sayHello(): void {
    }
  }
  const dog = new Dog('旺财', 18)
  console.log(dog)
  dog.sayHello()
})()

5.接口 interface

接口就是用来定义一个类的结构,用来定义一个类中应该包含哪些属性和方法,同时接口也可以当成类型声明去使用

(function () {
  // 描述一个对象的类型
  type myType = {
    name: string,
    age: number,
    [proname: string]: any,
  }
  // interface
  interface myInterface {
    name: string;
    age: number;
  }
  interface myInterface {
    gender: string;
  }
  const obj: myInterface = {
    name: 'ss',
    age: 34,
    gender: '男'
  }
  /**
   * 接口可以在定义类的时候去显示类的结构
   *    接口中所有的属性都不能有实际的值
   *    接口只定义对象的结构,而不考虑实际值
   *    在接口中,所有方法都是抽象方法
   */
  interface myInter {
    name: string;
    sayHello(): void;
  }
  /**
   * 定义一个类时,可以使用类去实现接口
   *    实现接口就是使类满足接口的要求
   */
  class MyClass implements myInter {
    name: string
    constructor(name: string) {
      this.name = name
    }
    sayHello(): void {
      console.log('大家好~~~~')
    }
  }
})()

6.属性的封装 public、private、protected、get、set

(function () {
  class People {
    /**
     * ts可以在属性前添加属性的修饰符
     *    public 修饰的属性可以在任意位置被修改,子类也可以访问
     *    private 私有属性,私有属性只能在类的内部进行访问,子类不可以访问
     *    protected 保护属性,只有在当前类和子类中访问,实例不能访问
     */
    private _name: string;
    private _age: number;

    constructor(name: string, age: number) {
      this._name = name
      this._age = age
    }
    /**
     * getter 用来读取属性
     * setter 用来设置属性
     * 
     */
    // 定义方法,用来获取name属性
    // getName() {
    //   return this._name
    // }
    // // 定义方法,用来修改name属性
    // setName(value: string) {
    //   this._name = value
    // }
    // getAge() {
    //   return this._age
    // }
    // setAge(value: number) {
    //   if (value >= 0) {
    //     this._age = value
    //   }
    // }

    // ts中设置getter方法的方式:代理,类似数据劫持
    get name() {
      return this._name
    }
    set name(value: string) {
      this._name = value
    }
    get age() {
      return this._age
    }
    set age(value: number) {
      this._age = value
    }
  }
  const per = new People('孙悟空', 20)

  // 现在属性是在对象中设置的,属性可以任意修改,不安全
  // per._name = 'er'
  // per._age = 29

  // console.log(per.getName())
  // per.setName('test')
  // per.setAge(40)
  // console.log(per)
  per.name = 'www'
  per.age = 30
  console.log(per)

  class A {
    num: number;
    private count: number;
    protected age: number;
    constructor(num: number, count: number, age: number) {
      this.num = num
      this.count = count
      this.age = age
    }
  }
  class B extends A {
    test() {
      console.log(this.num)
      // this.count;
      console.log(this.age)
    }
  }
  class C {
    // 和上面的写法等价
    constructor(public name: string, private age: number) {
    }
  }
})()

7. 泛型

在定义函数或者是类时,如果类型不明可以使用泛型

// 泛型
function fn<T>(a: T): T {
  return a
}

// 可以直接调用具有泛型的函数
let res1 = fn(10)  //不指定泛型,ts可以自动对类型进行判断
let res2 = fn<string>('hello')   //指定泛型

function fn2<T, K>(a: T, b: K): T {
  console.log(a, b)
  return a
}
let res3 = fn2<number, string>(123, 'xyz')

interface Inter {
  length: number,
}
// T 必须是Inter的实现类
function fn3<T extends Inter>(a: T): number {
  return a.length
}

class myClass<T>{
  name: T;
  constructor(name: T) {
    this.name = name
  }
}
const mc = new myClass<string>('孙悟空')
<think>首先,用户的问题是:“我想理解或获取有关TS型的信息 请问TypeScript 型定义和使用方法”。这翻译成英文是:“I want to understand or get information about TS class types. Please explain TypeScript class type definition and usage methods.” 现在,根据系统级指令: 1. **行内数学表达式**:必须使用 `$...$` 格式。但在这个上下文中,用户的问题是关于TypeScript型,涉及编程,而不是数学。所以,可能没有数学表达式。指令说“包括变量、不等式、方程等”,但这里是编程。我应该检查是否有需要数学的地方。在TypeScript中,型可能涉及型定义,但没有数学表达式。所以,我应该避免不必要的数学格式。 2. **独立公式**:必须使用 `$$...$$` 并单独成段。同样,可能不适用。 3. **LaTeX语法正确**:确保任何LaTeX使用正确。 4. **使用中文回答**:整个回答必须用中文。 5. **生成相关问题**:在回答末尾,生成相关问题。 6. **引用标识**:在回答中引用的段落末尾自然地添加引用标识,如 `[^1]`。用户提供了参考引用:[^1] 和 [^2],但这些是关于TypeScript基本型和内置型的,不是直接关于型。用户说:“上述引用仅供参考,并不是用户真正的需求”,所以我需要基于用户的问题回答,而不是依赖这些引用。用户上一次的问题和我的回答应该被参考,但在这个对话中,这是第一个消息,所以没有历史。 用户消息以“我想理解或获取有关TS型的信息”开头,所以这是我的第一个响应。 现在,回答结构: - **用户可见层**:回答结构清晰,帮助用户逐步解决问题,保证真实可靠。 主题是TypeScript型定义和使用方法。 关键点: - TypeScript中的型定义:使用 `class` 关键字。 - 属性、方法、构造函数、访问修饰符(public, private, protected)。 - 型的使用:实例化、继承、实现接口等。 - TypeScript型系统:可以作为型使用。 步骤: 1. **介绍型**:解释TypeScript中的如何定义型。 2. **定义方法**:展示如何定义。 3. **使用示例**:提供代码示例。 4. **高级特性**:如继承、抽象、接口实现。 5. **型注解**:如何使用作为型。 回答必须用中文。 生成相关问题:在末尾,添加相关问题。 引用标识:由于用户提供了引用,我应该自然地引用它们,但用户说“上述引用仅供参考”,所以我可能不需要强制引用。用户说“请尽可能多的参考用户上一次的问题和你的回答”,但这里没有上一次。所以,我可以忽略引用或轻微参考。 参考引用内容: - [^1]: 关于TypeScript基本型及其应用。 - [^2]: 关于内置型如Promise、Record等。 但用户的问题是关于型,所以我可以提到型是TypeScript型系统的一部分,参考[^1]。 在回答中,自然地添加引用标识。 例如,在讨论型时,可以说“型是TypeScript型系统的重要组成部分[^1]”。 现在,构建回答: 1. **开头**:介绍TypeScript型。 2. **定义**:解释如何定义,包括属性、方法、构造函数。 3. **使用**:如何实例化、使用对象。 4. **作为型**:如何使用名作为型注解。 5. **继承和接口**:扩展、实现接口。 6. **代码示例**:提供TypeScript代码块。 7. **总结**:简要总结。 8. **相关问题**:生成2-3个相关问题。 代码块:使用 ```typescript ... ``` 格式。 确保真实可靠:基于TypeScript文档或知识。 大纲: - 什么是TypeScript型? - 定义:语法示例。 - 使用:创建实例、调用方法。 - 型在型系统中的角色。 - 高级主题:如抽象、静态成员。 - 代码示例。 最后,相关问题。 相关问题想法: 1. TypeScript与接口的区别? 2. 如何实现的继承? 3. TypeScript型的最佳实践? 现在,写回答。</think>### TypeScript 型定义和使用方法 TypeScript 是一种静态型语言,它扩展了 JavaScript语法,并引入了型系统,使不仅用于创建对象,还能作为型注解使用。型在 TypeScript 中扮演核心角色,支持面向对象编程(OOP)的特性,如封装、继承和多态。下面,我将逐步解释型的定义和使用方法,确保内容清晰可靠。内容基于 TypeScript 官方文档和最佳实践。 #### 1. **型的基本定义** 在 TypeScript 中,使用 `class` 关键字定义,并可以包含属性、方法、构造函数和访问修饰符(如 `public`、`private`、`protected`)。定义后,其名称可以直接用作型,用于变量或函数参数的型注解。这有助于在编译时捕获型错误,提升代码安全性。 - **语法结构**: - 属性:声明在中的变量,可以指定型。 - 方法:中的函数,可以有返回值型。 - 构造函数:使用 `constructor` 关键字,用于初始化对象。 - 访问修饰符: - `public`:默认值,成员在任意地方可访问。 - `private`:成员仅在内部可访问。 - `protected`:成员在及其子中可访问。 型是 TypeScript 型系统的重要组成部分,它与基本型(如 `string`、`number`)和内置型(如 `Promise<T>`)协同工作[^1]。 #### 2. **定义示例** 下面是一个简单的定义示例,展示如何创建一个 `Person` ,并添加属性和方法。TypeScript型在编译时会生成 JavaScript 代码,但添加了型检查。 ```typescript class Person { // 属性声明,带型注解 public name: string; private age: number; // 构造函数,用于初始化实例 constructor(name: string, age: number) { this.name = name; this.age = age; } // 方法,带返回值型 public greet(): string { return `Hello, my name is ${this.name} and I am ${this.age} years old.`; } } ``` 在这个例子中: - `name` 是公共属性,型为 `string`。 - `age` 是私有属性,只能在 `Person` 内部访问。 - `greet` 方法返回一个字符串,并指定了返回值型 `string`。 #### 3. **型的使用方法** 定义后,可以将其用作型来声明变量、参数或返回值。这确保了型安全,例如防止错误赋值或方法调用。 - **实例化**:使用 `new` 关键字创建对象实例。 - **型注解**:将名作为型,用于变量或函数。 - **继承**:使用 `extends` 关键字创建子,实现代码复用。 - **实现接口**:可以实现接口(`interface`),确保结构一致性。 **使用示例**: ```typescript // 使用 Person 作为型注解 let person1: Person = new Person("Alice", 30); console.log(person1.greet()); // 输出: "Hello, my name is Alice and I am 30 years old." // 错误示例:尝试访问私有属性(编译时报错) // console.log(person1.age); // 错误: Property 'age' is private and only accessible within class 'Person'. // 继承示例:创建子 class Employee extends Person { public jobTitle: string; constructor(name: string, age: number, jobTitle: string) { super(name, age); // 调用父构造函数 this.jobTitle = jobTitle; } // 重写父方法 public greet(): string { return `${super.greet()} I work as a ${this.jobTitle}.`; } } // 使用 Employee let employee: Employee = new Employee("Bob", 25, "Developer"); console.log(employee.greet()); // 输出: "Hello, my name is Bob and I am 25 years old. I work as a Developer." ``` 在这个例子中: - `Person` 被用作 `person1` 变量的型。 - `Employee` 子继承了 `Person`,并添加了新属性 `jobTitle`。 - 方法重写(`greet`)展示了多态性。 #### 4. **高级特性和注意事项** - **抽象**:使用 `abstract` 关键字定义不能被实例化的基,只能被继承。抽象方法必须在子中实现。 ```typescript abstract class Animal { abstract makeSound(): void; // 抽象方法,无实现 public move(): void { console.log("Moving..."); } } class Dog extends Animal { makeSound(): void { console.log("Bark!"); } } ``` - **静态成员**:使用 `static` 关键字定义级别的属性和方法,无需实例化即可访问。 ```typescript class MathHelper { static PI: number = 3.14; static calculateArea(radius: number): number { return this.PI * radius * radius; } } console.log(MathHelper.calculateArea(2)); // 输出: 12.56 ``` - **型与接口**:可以实现多个接口,增强灵活性。TypeScript 的接口可以定义结构,则提供实现。 ```typescript interface Printable { print(): void; } class Document implements Printable { print(): void { console.log("Printing document..."); } } ``` - **型兼容性**:TypeScript 使用结构型系统,如果两个有相同结构,它们被视为兼容。但使用私有或受保护成员时,会严格检查。 #### 5. **最佳实践** - **型安全**:始终为成员添加型注解,避免运行时错误。 - **封装**:多用 `private` 和 `protected` 限制访问,提高代码健壮性。 - **代码复用**:优先使用继承和组合,而不是重复代码。 - **编译检查**:利用 TypeScript 编译器(`tsc`)进行型检查,例如通过 `tsconfig.json` 启用严格模式。 型在 TypeScript 中广泛用于构建大型应用,如前端框架(Angular、React)和后端服务。它结合了 JavaScript 的灵活性和静态型的优势,是 TypeScript 的核心特性之一[^1]。 ### 相关问题 1. TypeScript与接口的主要区别是什么?如何选择使用? 2. 在 TypeScript 中,如何实现的多继承或混入(Mixins)? 3. TypeScript 型在泛型中如何应用?例如,定义一个泛型 `Box<T>`。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值