03-TypeScript-泛型和类
2020-10-01 本文已影响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
}