TypeScript | TS从入门到放弃系列之第一章“入门”

265 阅读8分钟

以此篇,来开启自己的TypeScript学习之旅
>                             --Tricia

认识TypeScript

TypeScript 简称:TS,是 JavaScript 的超集 ,简单来说就是:JS 有的 TS 都有

  • TypeScript = Type + JavaScript(在 JS 基础之上,为 JS 添加了类型支持
  • TypeScript 是微软开发的开源编程语言,可以在任何运行 JavaScript 的地方运行

为什么要有typescript

js缺点?

  • JS 的类型系统存在“先天缺陷”弱类型,JS 代码中绝大部分错误都是类型错误(Uncaught TypeError)

    • 开发的时候,定义的变量本应该就有类型
  • 这些经常出现的错误,导致了在使用 JS 进行项目开发时,增加了找 Bug、改 Bug 的时间,严重影响开发效率

为什么会这样?

  • 从编程语言的动静来区分,TypeScript 属于静态类型的编程语言JavaScript 属于动态类型的编程语言

    • 静态类型:编译期做类型检查
    • 动态类型:执行期做类型检查
  • 代码编译和代码执行的顺序:1 编译 2 执行

  • 对于 JS 来说:需要等到代码真正去执行的时候才能发现错误(晚)

  • 对于 TS 来说:在代码编译的时候(代码执行前)就可以发现错误(早)

安装编译 TS 的工具包

Node.js和浏览器只认识 JS 代码,不认识 TS 代码。需要先将 TS 代码转化为 JS 代码,然后才能运行

安装命令:

npm i -g typescript  
# 或者
yarn global add typescript

ts简单数据类型

ts类型分为两大类

  1. js已有类型
  2. ts新增类型

let num :number = 100
let str :string = 'hello'
let boo :boolean = true
boo = !0
let param :null = null
let param2 :undefined = undefined

// any类型可以赋值给任意类型
let any :any = 'hello'
any = 100
// void类型只能赋值undefined和null
let voids :void = undefined
// let voids1 :void = null
// never类型表示永远不存在的值
// never类型只能赋值给never类型

类型别名

  • 类型别名(自定义类型):为任意类型起别名 推荐大写开头

    • type 自定义类型别名 = 类型
  • 使用场景:当同一类型(复杂)被多次使用时,可以通过类型别名,简化该类型的使用

type MyType = (string | number | boolean)[]
let arr : MyType = [1,'a',true]
let arr2 : MyType = [1,'a',false, 888, 'hshs']
let arr3 : MyType = [1, 888, 'hshs', false]

type MyVarType = number | string | boolean
let param1 : MyVarType = 'hello'
let param2 : MyVarType = true
let param3 : MyVarType = 100

ts复杂数据类型

数组类型

方式一

let 变量名 :类型注解[] = [值]

// 表示数组中只能存数字
let arr :number[] = [1,2,3] 
// 表示数组中只能存字符串
let arr2 :string[] = ['a','b','c']

方式二

let 变量名 :Array<类型注解> = [值]

let arr3 :Array<number> = [1,2,3]
let arr4 :Array<string> = ['a','b','c']
let arr5 :Array<boolean> = [true,false,!0]

联合类型

联合类型将多个类型组合成一个类型

{
//  联合类型
// temp变量,可以存 string number Boolean 三种类型
let temp : string | number | boolean = 100
temp = 'hello'
temp = true
// 实际应用中存定时器id 默认会给null,后面会改成number
let timeId : number | null = null
timeId = window.setInterval(() => {
  console.log('hello')
}, 1000)

// 需求 数组中可以存数字,字符串,也可以存布尔值
let arr : (boolean | number | string)[] = [1,'a',true]
let arr2 : Array<boolean | number | string> = [1,'a',false]
}

函数类型

基本类型

  • 函数指定类型:其实是在给函数的参数和返回值指定类型

    • function 函数名(参数1 : 类型, 参数2 : 类型) : 返回值类型 {函数体}
  • 为函数指定类型的两种方式:

    1. 单独指定参数、返回值的类型
    function add(n : number, m : number) : number {
        return n + m
      }
      add(1, 2)
    
      const sub = (n : number, m : number) : number => {
        return n - m
      } 
      sub(20, 10)
    
      const fn = function(n : number, m : number) : number {
        return n * m
      }
      fn(1, 2)
    
    1. 使用自定义类型 同时指定参数、返回值的类型(不常用)

      1. type 自定义类型 = (参数1 : 类型, 参数2 : 类型) => 返回值类型
    // 自定义函数类型   只适用于函数表达式和箭头函数
      // type 自定义类型 = (参数1 : 类型, 参数2 : 类型) => 返回值类型 
      type MyFnType = (n : number, m : number) => number
      const sub : MyFnType = (n , m) => {
        return n - m
      } 
      sub(20, 10)
    
      const fn : MyFnType = function(n , m) {
        return n * m
      }
      fn(1, 2)
    

void类型

如果函数没有返回值,那么,函数返回值类型为:void

// 如果函数没有返回值,那么,函数返回值类型为:void
const fn2 = () => {}

// 这种写法是明确指定函数返回值类型为 void,与上面不指定返回值类型相同
const fn3 = () : void => {
  console.log('hello')
}

// 如果指定 返回值类型为 undefined,此时,函数体中必须显示的 return undefined 才可以
const fn4 = () : undefined => {
  return undefined
}

可选参数

  • 可选参数,可以不传参数,也可以传参数

  • 可选参数:在可传可不传的参数名称后面添加 ?(问号)

  • 注意

    • 可选参数只能出现在参数列表的最后,也就是说可选参数后面不能再出现必选参数
function mySlice(start?: number, end?: number): void {
    console.log('起始索引:', start, '结束索引:', end)
  }

对象类型

TS 对象的类型就是在描述对象的结构 (有什么类型的属性和方法)

  • 写法

    • 使用 {} 来描述对象结构

    • 属性采用属性名: 类型的形式

    • 方法采用方法名(): 返回值类型的形式

      • 方法的类型也可以使用箭头函数形式

  // 对象类型说明
  type PersonType = {
    name: String,
    age: Number,
    gender: String,
    sing : (song : string) => void
    run() : void
  }

  const obj : PersonType = {
    name : 'Tt',
    age : 18, 
    gender : '女',
    sing : (song) => {
      console.log('我会' + song)
    }, 
    run() {
      console.log('跑800m 3min');
      
    },
  }
  obj.sing('小小小小小')
  

接口类型

当一个对象类型被多次使用时,一般会使用接口(interface)来描述对象的类型,达到复用的目的。

基础用法 ****

  1. 使用 interface 关键字来声明接口
  2. 接口名称(比如,此处的 IPerson),可以是任意合法的变量名称,推荐以 I 开头
  3. 声明接口后,直接使用接口名称作为变量的类型
  4. 因为每一行只有一个属性类型,因此,属性类型后没有 ;(分号)
interface IPersonType {
    name: String,
    age: Number,
    gender: String,
    sing : (song : string) => void
    run() : void
  }
  const obj : IPersonType = {
    name : 'Tt',
    age : 18, 
    gender : '女',
    sing : (song) => {
      console.log('我会' + song)
    }, 
    run() {
      console.log('跑800m 3min');
      
    },
  }
  obj.sing('小小小小小')

接口继承

interface实现继承 extends

  • 如果两个接口之间有相同的属性或方法,可以将公共的属性或方法抽离出来,通过继承来实现复用
  • 注意:不能调用可能是未定义的对象,所以调用时要加判断 stu1.sayHello && stu1.sayHello()
{
  // interface定义对象 还可以实现继承
  // 在ES6中 class类的继承使用extends关键字
  // class People { }
  // class Student extends People { }

  // 人的类型接口
  interface IPerson {
    name: string,
    age?: number,
    sayHello?(): void
    play?: () => void
  }

  // 学生的类型接口 继承于人的类型接口
  interface IStudent extends IPerson {
    grade: number
  }
  const stu1: IStudent = {
    name: 'Tricia',
    grade: 100,
    sayHello() {
      console.log('你好')
    },
  }
  // 注意:不能调用可能是未定义的对象,所以调用时要加判断
  // stu1.sayHello()
  stu1.sayHello && stu1.sayHello()
}

type实现继承 & |


  // 人的类型接口
  type IPerson = {
    name: string,
    age?: number,
    sayHello?(): void
    play?: () => void
  }

  // 动物的接口 
  type IAnimal = {
    eat(): void
  }

  // 学生的类型接口 继承于人的类型接口
  type IStudent = {
    grade: number
  } & IPerson & IAnimal

  type IWorker = {
  } & IPerson | IAnimal

  const stu1 : IStudent = {
    name: 'Tricia',
    grade: 100,
    sayHello() {
      console.log('你好')
    },
    eat() {
      console.log('吃吃吃')
    },
  }

  const worker : IWorker = {
    eat() {
      console.log('喝喝喝')
    },
  }
  worker.eat()
  stu1.sayHello && stu1.sayHello()

元组

元组: 特殊的数组 ---> 指定数组元素的类型 还要指定数组元素的个数


  // 数组中只能有两个元素 且均为数字类型
  let arr1 : [number, number] = [111, 222]
  // 数组中只能有两个元素 为键值对
  let arr2 : [string, number] = ['Tricia', 22]

类型推论

在 TS 中,某些没有明确指出类型的地方,TS 的类型推论机制会帮助提供类型

  1. 变量声明并赋值 推论
  2. 函数的返回值 推论

 let num = 100

 function fn (a: number, b: number) {
  return a + b + ''
 }

字面量类型

将一个固定的值设置为类型 这个就称为字面量类型,一般配合联合类型使用


  // 字面量类型    将一个固定的值设置为类型 这个就称为字面量类型,一般配合联合类型使用
  // str1 的类型为string  str2的类型为 Hello
  let str1 = 'haha'
  const str2 = 'Hello'
  // str2的完整写法:  const str2: 'Hello' = 'Hello'
  
  // 性别 只有两种
  let gender : 'man' | 'woman'
  gender = 'man'
 

枚举类型

如果没有提供默认值,从0开始递增。

数字枚举

// 枚举类型  如果没有提供默认值,从0开始递增
  enum Drictions {
    up,
    down,
    left = 88,
    right
  }

  function changeDirection (dir : Drictions) {
    console.log('方向改变' + dir)
  }
  changeDirection(Drictions.up)
  changeDirection(Drictions.down)
  changeDirection(Drictions.left)
  changeDirection(Drictions.right)

image.png

字符串枚举

{
  // 枚举类型  如果没有提供默认值,从0开始递增
  enum Drictions {
    up = '上',
    down = '下',
    left = '左',
    right = '右'
  }

  function changeDirection (dir : Drictions) {
    console.log('方向改变' + dir)
  }
  changeDirection(Drictions.up)
  changeDirection(Drictions.down)
  changeDirection(Drictions.left)
  changeDirection(Drictions.right)
}

image.png

异构枚举

enum Drictions {
    up = 10,
    down = '下',
    left = 88,
    right
  }

类型断言

有时候ts没有确定数据类型,我们可以使用类型断言明确一个数据类型

  1. as 后面加上明确的数据类型
// 获取一个类名叫.pic的img标签
  const img = document.querySelector('.pic') as HTMLImageElement
  console.log(img.src)
  1. 在前面使用 <>
// 获取一个div元素 
  const box = <HTMLDivElement> document.querySelector('div')
  console.log(box.innerHTML)