TypeScript核心

151 阅读8分钟

介绍

TypeScript 是具有类型语法的 JavaScript,是一门强类型的编程语言

它会将代码编译为js,运行js文件

优点

  • 能在编写的时候提前发现代码错误
  • 有代码提示

使用场景

一般小型开发不用ts比较占用性能

  • 大型的应用
  • 团队协作开发
  • 在编写通用的代码库

编译环境

ts编写的代码无法直接运行在js引擎(浏览器/Nodejs)中运行的,需要经过编译成js代码

搭建手动编译环境

  • 安装typescript包(编译引擎
    • 注册tsc命令 npm install typescript

      若安装在局部环境,需要在命令前加npx

    • 新增测试文件,执行 tsc 文件名.ts 命令生成hello.js文件
    • 执行node 文件名.js 文件查看内容
var message = 'hello,world';
console.log(message);

image.png

image.png

搭建工程化下的自动编译环境

手动编译环境需要使用命令行,可以看见编译后的js文件 自动编译环境不会再生成js文件,由环境辅助编译环境完成ts文件的执行

使用vite搭建

点击开始 | Vite 官方中文文档 (vitejs.dev)查看文档

使用命令

npm create vite@latest ts-pro -- --template vanilla-ts

  1. npm create vite@latest 使用最新版本的vite创建项目
  2. ts-pro 项目名称
  3. -- --template vanilla-ts 创建项目使用的模板为原生ts模板

image.png

执行图中的命令行

image.png

通过vscode打开

image.png

使用npm安装

创建根目录

  1. 安装typescript包

npm install typescript

image.png

安装后会生成这些文件

  1. 初始化配置文件

npm tsc --init

image.png

创建tsconfig.json 文件

  1. 修改tsconfig.json中的配置项
    • "rootDir": "./src", // 根目录
    • "outDir": "./dist", // 出口文件
  2. 创建目录 srcdist

image.png

  1. 执行代码查看效果

npx tsc -w

image.png

TS类型注释

若没有设置类型约束,ts会根据第一次初始化的值对变量进行类型约束

  • JS已有类型
    • 简单类型
      • number
      • string
      • boolean
      • null
      • undefined
    • 复杂类型
      • 数组
      • 函数
  • TS新增类型
    • 联合类型
    • 类型别名
    • 接口(interface)
    • 字面量类型
    • 泛型
    • 枚举
    • void
    • any

简单数据类型注释

let age: number = 18 // number类型注解
let uname: string = 'zhangsan' // string类型注解
let isWorking: boolean = true // 布尔值类型注解
let nullValue: null = null // null类型注解
let undefinedValue: undefined // undefined类型注解

console.log(age, uname, isWorking, nullValue, undefinedValue)

image.png

undefinednull是特殊值

ts.config.json中有"strictNullCheck"属性若改为false则可以进行空值传递(不检查空值)

image.png

数组类型注解

数组类型注解可以限制变量类型为数组,也可以限制数组成员的类型

编码的时候能提供数组和成员的属性和方法

两种数组类型注解方式:

  • 类型[]
let arr1: number[] = [1, 2, 3]
  • Array<number>
let arr2: Array<number> = [1, 2, 3]

函数类型注解

函数类型注解可以给传递的参数以及函数的返回值添加注解

基础类型

// 两数相加函数
function add(a: number, b: number): number {
  return a + b
}

add(1, 2)

let res: number = add(1, 2)
console.log(res)

image.png

函数表达式(箭头函数)

函数表达式有两种函数类型注解

  • 分开注解
// 两数相加函数
const res = (a: number, b: number): number => {
  return a + b
}

console.log(res(1, 2))

image.png

  • 整体注解(库文件)
// 两数相加函数
type AddFn = (a: number, b: number) => number

const res: AddFn = (a, b) => {
  return a + b
}
console.log(res(3, 2))

image.png

整体注解是通过类型别名来进行注解

// 两数相加函数
type AddFn = (a: number, b: number) => number

const res: AddFn = (a, b) => {
    return a + b
}

console.log(res(3, 2))

image.png

可选参数

在函数的形参中可以添加?表示当前的形参可传可不传。如果传值则保证参数类型正确

参数的后面可以直接赋值作为形参的默认值

ts中默认值和可选参数不能同时出现

// 可选参数(必须在所有参数的末尾)
function introduceMyself(name: string, age?: number): string {
  if(age) {
    return name + '今年' + age + '岁'
  }
  return name
}
console.log(introduceMyself('geniusXiang'))
console.log(introduceMyself('geniusXiang', 18))

image.png

无返回值 - void

在函数返回值的类型约束中添加void表示函数没有返回值

在JS中没有返回值,默认返回的是undefined.TS中undefined是一种明确的简单类型。如果返回值为undefined,则返回值必须是undefined

let arr: Array<number> = [1, 2, 3]
function eachArr(arr: number[]): void {
  arr.forEach(item => {
    console.log(item)
  })
}

eachArr(arr)

image.png

联合类型注解

可以将一个变量进行多个类型注解

let num: number | string
num = '123'

num可以是数字类型也可以是字符串类型

let num: number | string[]
num = ['123']

num可以是数字类型也可以是字符串数组类型

let num: (number | string)[]
num = [1, 2, 3, '4']

num可以是数字的数组也可以是字符串数组,也可以混合

类型别名

通过type关键词给类型起别名以达到方便复用的目的

一般类型别名使用大驼峰命名方式

type ItemType = number | string

let a: ItemType
a = '123'

type注解对象

在TS中对于对象的类型注释,除了使用interface还可以使用类型别名进行注释

type StayAtSchool = {
  studingDurationMinutes: number
  isDrinking?: boolean
}

let student1: StayAtSchool = {
  studingDurationMinutes: 30,
}

student1 = {
  studingDurationMinutes: 10,
  isDrinking: false
}

type + 交叉类型模拟继承

类型别名配合交叉类型&实现类型服用

// type 模拟继承(交叉类型&)

// 原价商品
type GoodsType = {
  id: string
  price: number
}

// 打折类型商品
type DiscountGoodsType = GoodsType & {
  discount: number
}

let goods: DiscountGoodsType = {
  id: '百事可乐',
  price: 2.7,
  discount: 0.9
}

console.log(goods)

image.png

并集

// 并集
type GoodsType = {
  id: string
  price: number
}

type DisGoodsType = {
  price: number
  discount: number
}

let goods: GoodsType & DisGoodsType = {
  id: '可乐',
  price: 0.7,
  discount: 0.9
}

interface接口数据类型

一般接口数据类型使用大驼峰方式命名

interface常用于给对象添加类型约束,属性不可多不可少

interface Person {
  name: string
  age: number
  isWorking: boolean
}

const aa: Person = {
  name: 'geniusXiang',
  age: 18,
  isWorking: true
}

接口类型使用场景

  • 表单对象类型校验
interface LoginForm {
  username: string
  password: string
  isCheckingAgreement: boolean
}

const userOne: LoginForm = {
  username: 'geniusXiang',
  password: '123456',
  isCheckingAgreement: true
}
  • 渲染后端列表场景
// 渲染后端列表场景说明
interface Data {
  message: string
}

interface ResponseData {
  code: number
  data: Data
}

let dataSuccess = {
  code: 200,
  data: {
    message: '请求通过'
  }
}

let dataReject = {
  code: 500,
  data: {
    message: '你访问的页面丢失'
  }
}

接口的可选设置

通过可选符?对属性进行标记,该属性可有可无,若是有则要保证类型满足约束

interface StayAtSchool {
  studingDurationMinutes: number
  isDrinking?: boolean
}

let student1: StayAtSchool = {
  studingDurationMinutes: 30,
}

student1 = {
  studingDurationMinutes: 10,
  isDrinking: false
}

interfance的继承

接口的属性可以使用extends实现接口的继承

// 原价商品
interface GoodsType {
  id: string
  price: number
}

// 打折类型商品
interface DiscountGoodsType extends GoodsType {
  discount: number
}

let goods: DiscountGoodsType = {
  id: '百事可乐',
  price: 3,
  discount: 0.9
}

interface 对比 type

  • 相同点
    • 都能描述对象类型
    • 都能实现继承,interface使用extends,type配合交叉类型
  • 不同点
    • type除了能描述对象还可以用来自定义其他类型
    • 同名的interface会合并(属性取并集,不能出现类型冲突),同名的type会报错

字面量类型

使用 js字面量 作为类型对变量进行约束.字面量类型比普通的类型更加精确

// 普通的number类型 可以赋值任何数值
let count: number
count = 100
count = 200

// 字面量类型100 只能赋值为100
let count1: 100
count1 = 100

实际应用

type Gender = '男' | '女'
let gender:Gender = '男'
gender = '女'

例如element-ui中的button属性

type Props = {
  type: 'primary' | 'success' | 'danger' | 'warning'
}

字面量类型与const

let str1 = 'this is str' // str1 是string类型

const str2 = 'this is const string' // str2是字面量类型

const声明常量称之为常量,常量不能进行重新赋值

image.png

image.png

any 任意类型

// any
let a: any = 'hello, world'
a = true
a = 100
a = null
a = undefined
a = []
a = () => {}
a = {}

// 使用场景
function fn1(...rest: any[]) {}

unknown 未知类型

标记为unknown类型的可以赋值给其他类型

// unknown
let u: unknown
u = 100
u = null
u = undefined
u = []
// ......

unknownany

  • 相同点:都可以接收其他数据类型
  • 不同点:unknown类型的数据无法赋值给其他类型的数据

never

never一般使用较少,表示永不存在的值,常用于标注一个函数抛出错误时的返回值

// never
let fn1 = (): never => {
  throw new Error('出错啦')
}

tuple 元组

元组的概念只存在于ts中

  1. 长度固定
  2. 每个位置上的元素类型固定
// 数组
let list1: (string | number)[] = [1, 2, 3, 'a', 'b', 'c']
// 元组
let list2: [string, number] = ['abc', 100]

枚举类型

// 枚举类型
enum Male {
  man = '男',
  woman = '女'
}

console.log(Male.man)

enum list {
  s1,
  s2,
  s3
}
console.log(list.s1, list.s2, list.s3)

image.png

类型断言

  • 类型推断:在不进行标注的情况下,ts根据赋值进行自动的标注
  • 类型断言:手动的进行判断(少用,类型断言容易导致判断失误)
// const app = document.querySelector('#app') as HTMLDivElement
// const content = app.innerHTML
// console.log(content)

// const app = document.querySelector('#app')! //非空断言
// const content = app.innerHTML
// console.log(content)

// const app = document.querySelector('#app')
// const content = app?.innerHTML // 可选判断
// console.log(content)

const app = document.querySelector('#app')
if(app) {
  const content = app.innerHTML
  console.log(content)
}

泛型

通过泛型,可以动态的设置类型参数。比如定义一个函数的时候,参数的类型并不确定,那么可以让用户在调用函数的时候传入具体参数类型即可

// 泛型
function fn1<T>(param: T) {
  console.log(param)
}

fn1<number>(123)

// 定义对象的时候使用泛型
type objType<T> = {
  user: string,
  info: T
}

泛型通过extends实现继承

const obj: objType<string> = {
  user: 'zs',
  info: 'eating'
}

// 可以通过extends实现继承
function getLength<T extends string>(args: T) {
  return args.length
}

// getLength('hello,world')

泛型继承自定义对象

// 继承自定义对象
type obj = {
  length: number,
}
function getLength<T extends obj>(arg: T):number {
  return arg.length;
}