十分钟教你玩转TypeScript,快来看看这份TS保姆级教程,简单易懂

143 阅读8分钟

TypeScript 学习笔记

1.准备工作

要想编译ts文件必须安装TS的工具包,这个安装包可以将TS代码转为JS代码,然后才能运行

安装命令

    npm i -g typescript  //安装命令

typescript 包:用来编译TS代码的包,提供了 TSC 命令,实现了 TS -> JS 的转化

image.png

2.编译并且运行TS代码

  1. 创建hello.ts 文件
  2. 将TS编译为JS:在终端输入命令, tsc hello.ts
  3. 执行JS命令:在终端中输入命令, node hello.js

image.png

3.简化运行TS步骤

当前我如果修改代码后,都需要重复执行两个命令,才能执行TS代码,过于繁琐

  • 简化方法:使用ts-node包,直接在Node.js中执行TS代码
  • 安装命令:npm i -g ts-node
  • 使用方式:ts-node hello.ts
  • 原理:ts-node命令内部偷偷的将TS -> JS,再运行JS代码

4.TypeScript常用类型

4.1 类型注解

作用就是为变量添加类型约束,约定了什么类型,就只能给变量赋值该类型的值,否则就会报错

let age:number=18
age=12         //正确
age='12'       //类型错误

4.2 常用基础类型概述

可以将TS中的常用基础类型细分为两类:1.JS已有类型 2.TS新增类型

  • JS已有类型
    • 原始类型:number/string/boolean/null/undefine/symbol
    • 对象类型:object(包括,数组、对象、函数等对象)
  • TS新增类型
    • 联合类型、自定义类型(类型别名)、接口、元组、字面量类型、枚举、void、any等

1. 原始类型

特点:简单,这些类型,完全按照js中类型的名称来书写

2. 数组类型

两种写法:(推荐使用第一种)

    let numbers: number[] = [1, 2, 3, 4];
    let strings: Array<string> =['a','b','c']

需求:数组中既有number类型,又有string类型,这个数组的类型怎么写?

3. 联合类型

使用一根 | 竖线来表示联合

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

4. 类型别名(自定义类型)

当同一类型(复杂)被多次使用时,可以通过类型别名,简化该类型的使用(相当于在申明变量)

type CustomArray = (number|string)[]   //类型别名

let arr2:CustomArray = [1,2,3,'sd','we']
let arr3:CustomArray = ['sd','we',1,2]

5. 函数类型

函数的类型实际上指的是:函数参数和返回值的类型。 为函数指定类型的两种方式:1.单独指定参数、返回值的类型 2.同时指定参数、返回值的类型。

const add = function(name: string, age: number): void {
    console.log(`你好,我的名字叫${name},我的年龄是${age}岁`);

    //这里使用模板字面量,好处是:模板字面量通常更易于阅读和维护,
    //尤其是在处理包含多个变量或复杂表达式的字符串时,
    //对于非常长的字符串或大量的拼接操作,模板字面量可能会稍微快一些,
    //因为它们在内部使用更高效的方法来处理字符串和变量的组合
}

add('wjw',23)
type addType = (name: string, age: number,address?:string)=> void

const addmethod:addType = function(name,age,address?){
    if(address!==null||address!==undefined){
        console.log(`你好,我的名字叫${name},我的年龄是${age}岁,我的家在${address}`);
    }
    else
        console.log(`你好,我的名字叫${name},我的年龄是${age}岁`);
}

addmethod('yke',20,'莲湖')

6. 对象类型

JS中的对象由属性和方法构成,而TS中的对象的类型就是在描述对象的结构


//定义一个对象类型
type objType = {
  name: string;
  age: number;
  getName(): string;
  getAge?(): number;  //对象的可选函数
};

//创建一个objType类型的对象
let person: objType = {
  name: "wjw",
  age: 18,
  getName: function () {
    return this.name;  //这里使用this的话,方法就不能写成箭头函数
  },
  getAge: function () {
    console.log(`你好${JSON.stringify(this)},我刚满${person.age}`);
    return person.age;
  },
};

person.getAge!();  //调用可选函数必须加上! 断言
可选属性和方法
  • 比如在使用axios({...})时,如果发送的是GET请求,method就可以省略,使用“ ? ”来表示
function myAxios(config:{url: string;method?:string}){ //使用?来表示method是可选属性
    console.log(config);
}

7. 接口

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

interface IPerson{
    name: string
    age: number
    sayHi(name?:string): void
}

let person2: IPerson={
    name: "wjw",
    age: 18,
    sayHi: function (name?: string | undefined): void {
        let defaultName='默认名称'
        defaultName=name?name:defaultName
        console.log(`${defaultName},你好,${this.name}`)
    }
}

person2.sayHi('wjw2')
7.1 interface(接口)和type(类型别名)的区别
  • 相同点:都可以给对象指定类型
  • 不同点:
    • 接口:只能为对象指定类型
    • 类型别名:不仅可以为对象指定类型,实际可以为任意类型指定别名
7.2 接口继承

如果两个接口之间有相同的属性或方法,可以将公共的属性或方法抽离出来,通过继承实现复用

  1. 使用extends关键字实现接口的继承
  2. 继承后,继承的接口就有了被继承接口的所有属性和方法
interface IPoint1{
    x: number
    y: number
    getX(): number
    getY(): number
}

interface IPoint2{
    x: number
    y: number
    getX(): number
    z: number
}
//上述两个接口很多公共的属性和方法,重复写两次很繁琐,所以我们使用接口之间继承的方式

使用继承后:

interface IPoint1{
    x: number
    y: number
    getX(): number
    getY(): number
}

interface IPoint2 extends IPoint1{
    z:number
}

8. 元组

使用场景:在地图中,经常使用经纬度坐标来标记位置信息

可以使用数组来记录坐标,那么该数组中只有两个元素,并且这两个元素都是数组类型

let position:number[] = [32.123,54.123]

使用number[]的缺点:不严谨,因为该类型的数组中可以出现任意多个数字 更好的方式:使用元组

元组类型是另外一种类型的数组,它确切的知道包含了多少个元素,一级特定索引对应的类型

let position:number[number,number] = [32.123,54.123]

9. 类型推论

在TS中,某些没有明确指出类型的地方,TS的类型推论机制会帮助提供类型。换句话说:由于类型推论的存在,这些地方,类型推论可以不写。 发生类型推论的2种常见场景:1. 声明变量并且初始化 2. 决定函数返回值时


let num = 12 //声明变量并且初始化,类型推论生效,可以省略类型
num='123'    //报错

let result   //注意:如果只是声明变量,而没有初始化值,建议手动添加类型注解,不建议省略

result = 1    
result = '1'  //不报错

function add(num1:number,num2:number){//可以省略返回值的类型注解
    return num1+num2
}

10. 类型断言

有时候我们会比TS更能明确一个值的类型,此时,可以使用类型断言来指定具体的类型

类比java来说,我们拿到父类对象,但其实我们像调用子类的方法或者属性,那么我们就需要向下转型,因为父类里可能没有子类的方法或属性。同理,类型断言就是强制告诉TS我要的类型是什么

类型断言使用 as 关键字

const sonObject = father as son  //第一种写法

const sonObject  = <son>father   //第二种写法(不常用)

11. 字面量类型

先看以下两个变量的类型分别是什么?

let str1 = 'Hello'
const str2 = 'Hello'

通过TS类型推论机制,可以得到答案:

  1. 变量str1的类型为:string
  2. 变量str2的类型为:'Hello'

解释:str1是一个变量(let),他的值可以是任意字符串,所以类型是string。str2是一个常量(const),他的值不能变化只能是'Hello',所以,他的类型为'Hello'。

此处的'Hello',就是一个字面量类型,也就是说某个特定的字符串也可以作为TS中的类型

const str2:'Hello' = 'Hello'
let age:18 = 18

字面量类型通常配合联合类型一起使用,用来表示一组明确的可选值列表 比如在贪吃蛇游戏中,游戏的方向的可选值只能是:上下左右 中的任意一个

function changeDirection(direct:'up'|'down'|'left'|'right'){
    console.log(direct)
}

解释:参数direct的值只能是up/down/left/right 中的任意一个 优势:相比于string类型,使用字面量类型更加严谨准确

12. 枚举

枚举的功能类似于字面量类型+联合类型组合的功能,也可以表示一组明确的可选值

枚举:定义一组命名常量。他描述一个值,该值可以是这些命名变量中的一个

enum Direction {Up,Down,Left,Right}

function changeDirection(direct:Direction){
    console.log(direct)
    console.log(typeof direct)
}

changeDirection(Direction.Up)

上面我们把枚举成员作为了函数的实参,它的值是什么? 解释:通过鼠标移入Direction.Up,可以看到枚举成员Up的值为0

12.1 数字枚举

注意:枚举成员是有值的,默认为:从0开始自增的数值 我们把枚举成员的值为数字的枚举,称为:数字枚举。 当然,也可以给枚举中的成员初始化值


//Down=11,Left=12,Right=13
enum Direction {Up=10,Down,Left,Right}
enum Direction2 {Up=2,Down=5,Left=8,Right=10000}
12.2 字符串枚举

枚举成员的值是字符串 注意:字符串枚举没有自增长行为,因此,字符串枚举的每个成员必须有初始值

enum Direction{
    Up = 'UP',
    Down = 'DOWN',
    Left = 'LEFT',
    Right = 'RIGHT'
}

13. any类型

原则:不推荐使用any! 这会让TypeScript 变为 AnyScript (失去TS类型保护的优势)

14. typeof

TS中的typeof操作符可以在类型上下文中引用变量或属性的类型(类型查询) 使用场景:根据已有变量的值,获取该值的类型,来简化类型书写

let p = {x:1,y:2}

//我在定义函数时,函数参数类型可以由p.x这个属性来判断,如果该属性值是123,他的类型就是number,如果是'abc',他的类型就是string。这个类型就可以通过 typeof 来获取到
function change(point:typeof p.x){
    
}