TypeScript(四) —— 函数/接口/类/泛型语法总结

目录

  • 函数类型数组

    • 函数声明
    • 函数类型表达式
    • 可选参数
    • 任意个数的参数
  • 接口(interface)缓存

    • 定义接口
    • 使用接口
    • 选成员 & 只读成员 & 动态成员
  • app

    • 须要对类的属性与方法进行声明
    • 类成员访问修饰符(public/private/protected)函数

        1. 定义一个构造函数
        1. 初始化实例对象并访问构造函数成员
        1. 建立子类继承构造函数并访问其成员
    • 类的构造函数被私有化
    • 类的只读属性
    • 类与接口post

      • 定义接口
      • 实现接口
    • 抽象类学习

      • 抽象类定义
      • 子类继承
  • 泛型this

    • 定义泛型参数
    • 调用时传入泛型参数的类型
  • TypeScript学习地图

函数类型

函数的输入和输出进行约束,及参数和返回值spa

函数声明

// 参数的类型和返回值的类型
function func1(a: number, b: number): string {
    return 'func1'
}
// 参数类型和个数是固定的,不然报错
func1(100, 200)

函数类型表达式

// 普通函数
const func4 = function (a: number, b: number): string {
    return 'func2'
}
// 使用箭头函数
const func5: (a: number, b:number) => string = function(a, b) {
    return 'func2'
}

可选参数

可选参数必定要在必选参数后面,放在函数最后。rest

// 能够在b后面添加问号表示可选,也能够直接设置默认值,也能够不用传
function func2(a: number, b: number = 10, c?: number): string {
    return 'func1'
}

func1(100)

任意个数的参数

使用ES6rest操做符code

function func3(a: number, b: number = 10, ...rest: number[]): string {
    return 'func1'
}

func1(100,200,300,400)

接口(interface)

接口,是一种规范、契约,约定对象的结构。

接口是用来约束一个对象的结构,咱们要使用这个接口,就要遵循其所有的约定。

接口最直观的体现就是对象应该有哪些成员以及成员的类型都是什么样的?

定义接口

// 定义一个接口,里面肯定要有两个成员,且都是字符串类型
interface Post {
  title: string  // 结尾能够使用逗号分隔,也能够使用分号去分割,还能够省略
  content: string
}

使用接口

// 使用的时候声明参数是Post类型,里面使用的时候不担忧没有值
function printPost (post: Post) {
  console.log(post.title)
  console.log(post.content)
}

// title和content任何一个没有传或者不是字符串都会报错
printPost({
  title: 'this is a title',
  content:'this is a content'
})

可选成员 & 只读成员 & 动态成员

  • 可选成员 : 定义接口的时候添加问号,传参的时候无关紧要
interface Post {
  title: string
  content: string
  subtitle?: string // 可选成员,无关紧要,string or undefined
}

// 下面不传subtitle不会报错
const hello: Post = {
    title: 'this is a title',
    content:'this is a content'
}
  • 只读成员 :定义接口的时候前面添加readonly关键词,一经定义不能修改
interface Post {
  title: string
  content: string
  subtitle?: string
  readonly summary: string //只读成员,一经定义不能更改
}

const hello: Post = {
    title: 'this is a title',
    content:'this is a content',
    summary: 'this is a summary'
}

hello.summary = 'hello' // 报错
  • 动态成员 :不肯定有哪些成员,本身定义添加,通常这种都存在动态对象里面,例如程序中的缓存对象。

由于不知道有哪些成员名称,因此Cache里面使用[],指定键prop的类型是string,值的类型是number

interface Cache {
  [prop: string] : number
}

const cache: Cache = {}

cache['hello'] = 1
cache['hi'] = 2

类用来描述一类具体事物的抽象特征。TypeScript加强了class的相关语法,访问修饰符以及抽象类的概念等...

下面看一下TypeScript新增的内容:

须要对类的属性与方法进行声明

目的是为了给属性和方法作类型标注

class Person {
  // 须要对类的属性进行声明,能够添加默认值,也能够不添加
  // 二者有一个没有写,都会报错
  name: string = 'init name'
  age: number
  
  constructor (name: string, age: number) {
    // 若是不加声明,这里直接使用会报错,由于在TypeScipt须要明确属性,而不是动态添加
    this.name = name
    this.age = age
  }
  
  // 方法这些和以前是同样的,也要添加类型注解
  sayHi (msg: string): void {
    console.log(`I am ${this.name}, ${msg}`)
  }

  run (): void {
    this.sayHi('I am happy!')
  }
}

类成员访问修饰符(public/private/protected)

- public private protected
内部访问
外部访问 不可 不可
子类访问 不可
1. 定义一个构造函数
class Person {
  // 默认是public,加不加效果同样,建议去加
  public name: string = 'init name'
  // age属性是个私有属性,私有属性能够在函数内部经过this.age去访问
  private age: number
  // 受保护的,外界成员不可访问,子类成员能够访问
  protected gender: boolean

  constructor (name: string, age: number) {
    this.name = name
    this.age = age
    this.gender = true
  }

  sayHi (msg: string): void {
    console.log(`I am ${this.name}, ${msg}`)
    console.log(this.age) //本身内部访问私有属性是没有问题的
    console.log(this.gender) //本身内部访问受保护属性是没有问题的
  }
}
2. 初始化实例对象并访问构造函数成员
const xm = new Person('xm', 18)
console.log(xm.name)
console.log(xm.age) // 报错,Property 'age' is private and only accessible within class 'Person'
console.log(xm.gender) // 报错,Property 'gender' is protected and only accessible within class 'Person' and its subclasses.
3. 建立子类继承构造函数并访问其成员
//定义一个Student类继承Person
class Student extends Person {
  constructor(name: string, age: number) {
    super(name, age)
    console.log(this.gender)
    console.log(this.age) // 报错,私有成员不能访问
    console.log(this.name)
  }
}

类的构造函数被私有化

  • private: 若是类的构造函数被私有化,那么不能被实例化和继承,这个时候只能在这个类的内部添加一个静态方法,经过静态方法添加实例。
  • protected: 若是类的构造函数被受保护,那么不能实例化,可是能够继承。
class Student extends Person {
  private constructor(name: string, age: number) {
    super(name, age)
    console.log(this.gender)
    console.log(this.name)
  }
  // 能够定义一个方法内部实例化
  static create (name: string, age: number) {
    return new Student(name, age)
  }
}

const xm = Student.create('xm', 18)
console.log(xm.name)

类的只读属性

在属性前添加修饰符readonly,若是有访问修饰符,那么就跟在修饰符的后面.只读属性必须在声明时或构造函数里被初始化。

class Person {
  public name: string = 'init name'
  private age: number
  // 若是有访问修饰符,那么就跟在修饰符的后面
  protected readonly gender: boolean

  constructor (name: string, age: number) {
    this.name = name
    this.age = age
    this.gender = true
  }

  sayHi (msg: string): void {
    console.log(`I am ${this.name}, ${msg}`)
    console.log(this.gender = false) // Cannot assign to 'gender' because it is a read-only property.
  }

  run (): void {
    this.sayHi('I am happy!')
  }
}

let xm = new Person('xm', 18)
xm.gender = 'false' // 报错

类与接口

类与类之间的公共特征通常会用接口去抽象

好比下面两个不一样的类,可是都有eatrun两个相同的方法,能够用接口约束两个类中公共的部分

class Person {
  eat (food: string): void {
    console.log(`优雅进餐:${food}`)
  }

  run (distance: number) {
    console.log(`直立行走:${distance}`)
  }
}

class Animal {
  eat (food: string): void {
    console.log(`不优雅进餐:${food}`)
  }

  run(distance: number) {
    console.log(`爬行:${distance}`)
  }
}
定义接口
// 能够定义一个接口实现一个能力,而后让一个类实现多个接口

interface Eat {
  eat (food: string): void
}

interface Run {
  run (distance: number): void
}
实现接口
// Person和Animal要实现接口,若是里面少了接口对应的方法,就会报错。
class Person implements Eat, Run{
  eat (food: string): void {
    console.log(`优雅进餐:${food}`)
  }

  run (distance: number) {
    console.log(`直立行走:${distance}`)
  }
}

class Animal implements Eat, Run{
  eat (food: string): void {
    console.log(`不优雅进餐:${food}`)
  }

  run(distance: number) {
    console.log(`爬行:${distance}`)
  }
}

抽象类

  • 抽象类与接口有些相似,也是约束子类中必需要有哪些成员,不一样的是抽象类里面能够包含一些具体的实现
  • 抽象类只能继承,不能实例化对象
  • 抽象类中能够定义一些抽象方法
  • 抽象方法不须要方法体,当父类中有抽象方法的时候,子类必需要实现抽象方法
抽象类定义
// 添加abstract关键词以后就成为了抽象类
abstract class Animal {
  eat (food: string): void {
    console.log(`不优雅进餐:${food}`)
  }
  // 抽象类中能够定义一些抽象方法,也须要关键词abstract
  abstract run (distance: number): void
}
子类继承
class Dog extends Animal {
  // 能够在VSCode环境点击Dog使用快速修复自动生成代码实现
  // 这里实现了抽象类中的run抽象方法
  run(distance: number): void {
    console.log('爬行', distance)
  }
}

// 子类实例化
const d = new Dog()
d.eat('粮食')
d.run(100)

泛型

咱们在定义函数、接口或者类的时候没有去指定类型,只有当使用的时候才去指定类型的一种特征。

其目的 就是为了极大程度复用咱们的代码

举个例子:

下面是传入长度和值,返回一个数组

// 参数长度是number类型,value是number类型,返回的是number类型的数组
function createArray (length: number, value: number): number[] {
  const arr = Array<number>(length).fill(value)
  return arr
}

// 下面传入参数能够得到三个值为100的数字类型的数组
const res = createArray(3, 100) // res => [100, 100, 100]

上面的代码有个缺陷是只能返回数字类型的数组,若是换成其余类型就会报错,如何进行修改?

定义泛型参数

  • 函数名后面使用尖括号,里面定义泛型参数
  • 通常泛型参数都用大写的T做为名称,函数中不明确的类型都用T去表明
function createArray <T> (length: number, value: T): T[] {
  const arr = Array<T>(length).fill(value)
  return arr
}

调用时传入泛型参数的类型

  • 调用时在函数名后面用尖括号内部填入参数的类型
// 下面能够填充字符串类型或者数字类型均可以
const res = createArray<string>(3, 'foo')
const res1 = createArray<number>(3, 100)

总结 就是泛型参数将定义时不能明确的参数用一个T来代替,使用的时候指定T的类型

TypeScript学习地图

相关文章
相关标签/搜索