TypeScript理论知识一

目录

一、TypeScript 优势

二、安装 TypeScript

三、TypeScript 基础类型

3.1 数组 2 种定义方式

3.2 元组 Tuple

3.3 枚举 enum

3.4 any 任何类型

3.5 void 没有任何类型

3.6 never 永不存在值的类型

3.7 使用 object 类型表示 Object.create API

3.8 类型断言 2 种形式

四、interface 接口

五、函数

六、类型推论、联合类型

七、Class 类、类与接口

八、泛型 Generics

九、类型别名和交叉类型

十、声明文件

十一、内置类型


一、TypeScript 优势

  • JavaScript 的超集

  • 支持 ES6 标准,并支持输出 ES 3 / 5 / 6 标准的纯 JS 代码

  • 支持 ES 未来提按中的特性,比如异步功能和装饰器

  • 支持类型系统且拥有类型推断

  • 支持运行在任何浏览器 、Node.js 环境中

Node.js 是 JS 一个基于服务端的运行环境,带 LTS 标记是稳定版,node 版本查询指令 node -v

npm 全称是 Node package Manager,翻译过来是 Node.js 的包管理工具,npm 与 Node.js 一起无痕地捆绑安装

Yarn 是一款新的 JS 包管理工具

 

二、安装 TypeScript

// 全局安装 TypeScript
npm install -g typescript

// TypeScript 版本查询
tsc -v

// TypeScript 编译成 JavaScript
tsc test.ts

// ts 文件编译成 es6
tsc test.ts target --es2015

// 全局监听 TypeScript
tsc test.ts --watch

// ts-node 提供直接运行 TypeScript 代码的能力
ts-node test.ts

 

三、TypeScript 基础类型

原始数据类型 7 个:Boolean、String、Number、Null、Undefined、BigInt、Symbol

Null、Undefined 是任何类型的子类型

// const 定义的变量必须赋初始值
const isDone: boolean = true
const str: string = 'Hello TypeScript'
const num: number = 123
const n: null = null
const u: undefined = undefined
const big: bigint = 20n
const sym: symbol = Symbol('独一无二的值')

3.1 数组 2 种定义方式

// 在元素类型后面接上 [],表示由此类型元素组成的一个数组
const arr1: number[] = [1, 2, 3]

// 使用数组泛型,Array<元素类型>
const arr2: Array<number> = [1, 2, 3]

3.2 元组 Tuple

// 已知元素数量和类型的数组,各元素的类型不必相同,元组里面的元素有顺序要求
const tuple: [string, number, boolean] = ['str', 1, true]

3.3 枚举 enum

/**
 * 枚举类型首字母大写 ,使用枚举类型可以为一组数值赋予友好的名字
 * 枚举类型提供便利由枚举的值得到它的名字
 * 枚举里面的值用逗号分隔
 */
// 数字枚举有正向映射(key->value)和反向映射(value->key),默认从 0 开始,也可以手动指定成员数值,后面的值依次递增
enum State {
  pending,
  fulfilled,
  rejected
}
const pending = State.pending
const first = State[0]
console.log(pending, first) // 0 'pending'

// 字符串枚举只有正向映射没有反向映射,字符串枚举没有递增的含义,字符串枚举成员都必须手动初始化
enum Direction {
  top = 'top',
  right = 'right',
  bottom = 'bottom',
  left = 'left'
}
const r = Direction.right
// const r = Direction['right'] // 访问属性 2 种形式都可以
console.log(r) // right

3.4 any 任何类型

// any 可以给变量设置任何类型,typescript 不做类型检查
let which: any = 123
which = 'str'
which = true

const arr: any[] = [123, 'str', true, null, undefined]

3.5 void 没有任何类型

/**
 * 当一个函数没有返回值时,通常会见到其返回值类型是 void
 */
function warnUser(): void {
  console.log('This is my warning message')
}
warnUser()

3.6 never 永不存在值的类型

/**
 * never 适用场景
 * 抛出异常 try...catch
 * 根本不会有返回值的函数表达式或箭头函数表达式的返回值类型
 * 变量也可能是 never 类型,当它们被永不为真的类型保护所约束时
 * 
 * never 类型是任何类型的子类型,也可以赋值给任何类型;
 * 然而,没有类型是 never 的子类型或可以赋值给 never 类型(除了 never 本身之外)
 * 即使 any 也不可以赋值给 never
 */

 // 返回never的函数必须存在无法达到的终点
function error(message: string): never {
  throw new Error(message)
}

// 推断的返回值类型为never
function fail() {
  return error("Something failed")
}

// 返回never的函数必须存在无法达到的终点
function infiniteLoop(): never {
  while (true) {
  }
}

3.7 使用 object 类型表示 Object.create API

declare function create(o: object | null): void
create({ prop: 0 })
create(null)

3.8 类型断言 2 种形式

/**
 * 类型断言好比其它语言里的类型转换,不进行特殊的数据检查和解构
 * 它没有运行时的影响,只是在编译阶段起作用
 */
// 使用 as 关键字
const val01: any = 'This is a string'
const len01: number = (val01 as string).length

// 使用“尖括号”:<元素类型>变量
const val02: any = 'This is a string'
const len02: number = (<string>val02).length

 

四、interface 接口

/**
 * interface 接口名首字母大写,接口是一个对象对属性类型进行描述
 * 接口定义函数参数的数据类型和函数参数的返回值类型
 * 可选属性用 ? 表示
 * readonly 只读属性,字段只能在创建的时候被赋值
 * 只读变量用 const
 */
// 定义一个 Person 接口
interface Person {
  name?: string
  age: number
  readonly height?: string
}

// 定义一个 student 变量,类型是 Person。约束 student 字段必须和 Person 字段一致
const student: Person = {
  name: '张三',
  age: 18,
  height: '180cm'
}
student.name = '李四'
// student.height = '170cm'
console.log(student)

 

五、函数

// 约定输入、输出,可选参数
function add(x: number, y: number, z?: number): number {
  if (typeof z === 'number') {
    return x + y + z
  } else {
    return x + y
  }
}
const result = add(1, 2, 3)
console.log(result)

// 函数本身类型
const add2: (x: number, y: number, z?: number) => number = add

// interface 接口描述函数类型
const sum = (x: number, y: number) => {
  return x + y
}
interface ISum {
  (x: number, y: number): number
}
const sum2: ISum = sum

 

六、类型推论、联合类型

/**
 * 类型推论:根据值推论出变量的数据类型
 * const 定义一个常量
 */
let str = 'str'
const num = 123

/**
 * 联合类型:用中竖线分割
 * 当 TS 不确定一个联合类型的变量到底是哪个类型的时候
 * 只能访问此联合类型的所有类型里共有的属性或方法
 */
let numberOrString: number | string
numberOrString.toString()
numberOrString.valueOf()
numberOrString.toLocaleString()

function getLength(val: number | string): number {
  // as 类型断言关键字,明确告知 TS 编译器,你没法判断我的代码,本人很清楚该变量的数据类型
  const str = val as string
  if(str.length){
    return str.length
  } else {
    const num = val as number
    return num.toString().length
  }
}

/**
 * 类型守卫
 */
function getLength01(val: number | string): number {
  if(typeof val === 'string'){
    return val.length
  } else {
    return val.toString().length
  }
}

 

七、Class 类、类与接口

Class 类定义了一切事物的抽象特点
对象 Object 是类的实例
面向对象 OOP 三大特性:封装、继承、多态
✦ 封装:对数据的操作细节隐藏起来,只暴露对外的接口。外界调用端不需要知道细节,就能通过对外提供的接口来访问该对象
✦ 继承:子类继承父类,子类除了拥有父类的所有特性外,还有一些更具体的特性
✦ 多态:由继承而产生了相关的不同的类,对同一个方法可以有不同的响应

类修饰符
✦ Public:修饰的属性或方法是公有的,可以在任何地方被访问到,默认所有的属性和方法都是 public
✦ Private:修饰的属性或方法是私有的,不能在声明它的类的外部访问
✦ Protected:修饰的属性或方法是受保护的,它和 private 类似,区别是它在子类中也是允许被访问的

 /** 
 * 类 Class:定义了一切事物的抽象特点
 * 对象 Object 是类的实例
 *
 * 面向对象 OOP 三大特性:封装、继承、多态
 * 封装:对数据的操作细节隐藏起来,只暴露对外的接口。外界调用端不需要知道细节,就能通过对外提供的接口来访问该对象
 * 继承:子类继承父类,子类除了拥有父类的所有特性外,还有一些更具体的特性
 * 多态:由继承而产生了相关的不同的类,对同一个方法可以有不同的响应
 * 
 * 类修饰符
 * Public:修饰的属性或方法是公有的,可以在任何地方被访问到,默认所有的属性和方法都是 public
 * Private:修饰的属性或方法是私有的,不能在声明它的类的外部访问
 * Protected:修饰的属性或方法是受保护的,它和 private 类似,区别是它在子类中也是允许被访问的
 */
class Animal {
   name: string
   constructor(name: string){
    this.name = name
   }
   run () {
     return `${this.name} is running`
   }
 }
 const snake = new Animal('lily')

 /**
  * 类的继承
  */
 class Dog extends Animal {
   bark() {
     return `${this.name} is barking`
   }
 }
 const xiaobao = new Dog('xiaobao')
 console.log(xiaobao.run())
 console.log(xiaobao.bark())

 /**
  * 重写构造函数,注意在子类的构造函数中,必须使用 super 调用父类的方法,不然会报错
  */
 class Cat extends Animal {
   constructor(name){
    super(name)
    console.log(this.name)
   }
   run() {
     return 'Meow, ' + super.run()
   }
 }
 const maomao = new Cat('maomao')
 console.log(maomao.run())

类和接口
类使用 implements 实现接口
实现多个接口,中间用逗号隔开

interface Radio {
  switchRadio(trigger: boolean): void // 开关收音机
}
class Car implements Radio { // implements 实现
  switchRadio(trigger) {
    return 123
  }
}
class Cellphone implements Radio {
  switchRadio() {}
}

interface Battery { // Battery 电池
  checkBatteryStatus(): void
}

// 实现多个接口,中间用逗号隔开即可
class Cellphones implements Radio, Battery {
  switchRadio() {}
  checkBatteryStatus() {}
}

八、泛型 Generics

泛型是指在定义函数、接口或类的时候,不预先指定具体的类型,而是在使用的时候再指定类型的一种特性

function echo(arg) {
  return arg
}
const result = echo(123)
// 此时发现一个问题,传入的是数字,返回的是 any

function echo02<T>(arg: T): T {
  return arg
}
const result02 = echo02(123)

// 泛型可以传入多个值
function swap<T, U>(tuple: [T, U]): [U, T] {
  return [tuple[1], tuple[0]]
}
const result03 = swap(['string', 123])

泛型约束
函数内部使用泛型变量的时候,由于事先不知道它是哪种类型,所以不能随意的操作它的属性和方法

function echoWidthArr<T>(arg: T): T {
  // console.log(arg.length)
  /**
   * 上面例子报错,泛型 T 不一定包含 length 属性,可以给他传入任意类型
   * 有些不包含 length 属性,就会报错
   */
  return arg
}

interface IWidthLength {
  length: number
}
function echoWidthLength<T extends IWidthLength>(arg: T): T {
  console.log(arg.length)
  return arg
}
echoWidthLength('str')
const result3 = echoWidthLength({ length: 10 })
const result4 = echoWidthLength([1, 2, 3])
console.log(result3, result4)

泛型与类和接口

class Queue { // Queue 队列
  private data = []
  push(item) {
    // push 把参数添加到数组项的尾部,返回的是新数组的长度
    return this.data.push(item) 
  }
  pop() {
    // shift 删除数组第一项,返回的是被删除的值
    return this.data.shift() 
  }
}
const queue = new Queue()
queue.push(1)
queue.push('str')
console.log(queue)
/**
 * 上述代码存在一个问题,它允许你向队列中添加任何类型的数据
 * 当数据被弹出队列时,也可以是任意类型
 * 上面示例中,看起来人们可以向队列中添加 string 类型的数据
 * 但在使用的过程中,会出现我们无法捕捉到的错误
 */

 // 类中使用泛型
 class Queue1<T> {
   private data = []
   push(item: T) {
    return this.data.push(item)
   }
   pop(): T{
     return this.data.shift()
   }
 }
 const queue1 = new Queue1<number>()


// 泛型和 interface
interface KeyPair<T, U> { // KeyPair 键值对
  key: T
  value: U
}
let kp1: KeyPair<number, string> = {key: 1, value: 'str'}
let kp2: KeyPair<string, number> = {key: 'str', value: 1}

九、类型别名和交叉类型

类型别名,就是给类型起一个别名,让它可以更方便的被重用

let sum: (x: number, y: number) => number
const result = sum(1, 2)
type PlusType = (x: number, y: number) => number
let sum2: PlusType

// 支持联合类型
type StrOrNumber = string | number
let result2: StrOrNumber = '123'
result2 = 123

// 字符串字面量
type Directions = 'Up' | 'Right' | 'Bottom' | 'Left'
let toWhere: Directions = 'Up'
console.log(toWhere)

交叉类型 Intersection Types

interface IName {
  name: string
}
type IPerson = IName & { age: number }
let person: IPerson = { name: 'hello', age: 12 }

 

十、声明文件

 

十一、内置类型

const a: Array<number> = [1, 2, 3]
/**
 * 大家可以看到这个类型,不同的文件中有多处定义,但是它们都是内部定义的一部分
 * 然后根据不同的版本或者功能合并在了一起,一个 interface 或者类多次定义会合并在一起
 * 这些文件一般都是以 lib 开头,以 d.ts 结尾,告诉大家,我是一个内置对象类型
 */
const date: Date = new Date()
const reg = /abc/
/**
 * 还可以使用一些 build in object 内置对象,比如 Math 与其他全局对象不同的是
 * Math 不是一个构造器, Math 的所有属性与方法都是静态的
 * Math.pow(x, y) x 的 y 次幂,x 是底数,y 是幂,x、y 必须是数字
 * 如果结果是虚数或负数,该方法将返回 NaN。如果由于指数过大而引起浮点溢出,则该方法将返回 Infinity
 */
Math.pow(2, 2) 

/**
 * DOM 和 BOM 标准对象
 * document 对象,返回的是一个 HTMLElement 对象
 */
let body: HTMLElement = document.body
// document 上面的 query 方法,返回的是一个 nodeList 类型
let allLis = document.querySelectorAll('li')

/**
 * 添加事件也是很重要的一部分,document 上面有 addEventListener 方法,这是一个回调函数
 * 因为类型推断,这里面的 e 事件对象也自动获得了类型,这里是个 mouseEvent 类型
 * 因为点击是一个鼠标事件,现在我们可以方便的使用 e 上面的方法和属性
 */
document.addEventListener('click', e => {
  e.preventDefault()
})

Typescript 还提供了一些功能性,帮助性的类型,这些类型,大家在 js 的世界是看不到的,这些类型叫做 utility types,提供一些简洁明快而且非常方便的功能

// partial,它可以把传入的类型都变成可选
interface IPerson {
  name: string
  age: number
}

let viking: IPerson = { name: 'vikong', age: 20 }
type IPartial = Partial<IPerson>
let viking2: IPartial = {}

// Omit,它返回的类型可以忽略传入类型的某个属性
type IOmit = Omit<IPerson, 'name'>
let viking3: IOmit = { age: 20 }

参考文档:http://docs.vikingship.xyz/typescript.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值