TypeScript学习(持续补充...)

xiaoniuyeye
·发布于 4 个月前
TypeScript

简介

  1. 由微软开发,是基于JS的一个扩展语言
  2. 包含JS所有内容,即TS是JS的超集
  3. TS增加了:静态类型检查,接口,泛型等很多现代开发特性,更加适合大型项目的开发
  4. TS需要编译为JS,然后交给浏览器或其他JS运行环境执行

为何引入TS

​ 简单来说,就是JS出现的太早,而现在用的地方很多,逐渐出现了很多的困扰。而目前需要想办法解决或者避免这些问题。比如:

  1. 不清楚的数据类型
  2. 有漏洞的逻辑
  3. 访问不存在的属性
  4. 低级的拼写错误

于是引出TS的核心:【静态类型检查】

静态类型检查是指在代码运行前进行检查,以发现代码的错误和不合理的地方,减小运行时出现异常的几率。(把运行时的错误前置)

显然要实现这些,TS的代码量肯定会多余JS,但TS结构会更加清晰,在后期的维护中TS也更优于JS。

编译TS

由于浏览器不能直接运行TS代码,需要编译为JS再交由浏览器解析器执行。

1.命令行编译

配置TS的编译环境,步骤:

  • 创建ts文件,比如demo.ts

  • 全局安装TypeScript

    npm i typescript -g

  • 使用命令编译.ts文件

    tsc demo.ts

2.自动化编译

  1. 创建TS编译控制文件

    tsc --init
    

    (1)工程中会生成一个tsconfig.json配置文件,其中包含很多编译时的配置

    (2)观察发现,默认编译的JS版本是ES7,我们可以手动调整为其他版本

  2. 监视目录中的.ts文件变化

    tsc --watch 或者 tsc -w
    
  3. 小优化,当编译错误时不生成.js文件

    tsc --noEmitOnError --watch
    

类型声明

使用**:**来对变量或函数形参

例如;

let a: string //变量a只能存储字符串

let b: number //变量b只能存储数值

let c: boolean //变量c只能存储布尔值

a = 'hello'

a = 100 //警告:不能将类型“number”分配给类型“string”

b = 666

b = '你好'//警告:不能将类型“string”分配给类型“number”

c = true

c = 666 //警告:不能将类型“number”分配给类型“boolean”

// 参数x必须是数字,参数y也必须是数字,函数返回值也必须是数字

function demo(x:number,y:number):number{

 return x + y

}

demo(100,200)

demo(100,'200') //警告:类型“string”的参数不能赋给类型“number”的参数

demo(100,200,300) //警告:应有 2 个参数,但获得 3 个

demo(100) //警告:应有 2 个参数,但获得 1 个

类型推断

TS会根据我们的代码,进行类型推断,例如如果一开始没有给变量声明类型,而是直接赋值后,后续只能给该变量使用最开始的数据类型。但注意,类型推断不是万能的,面对复杂类型时推断容易出错,所以尽量还是要明确编写类型声明!!!

let d = -99 //TypeScript会推断出变量d的类型是数字

d = false //警告:不能将类型“boolean”分配给类型“number

类型总览

JS中的数据类型

  • string
  • number
  • boolean
  • null
  • undefined
  • bigint
  • symbol
  • object

备注:其中object包含:Array,Function,Date,Errror等...

TS中的数据类型

上述所有的JS数据类型 + 六个新类型 +2个用于自定义类型的方式

  • any
  • unknown
  • never
  • void
  • tuple
  • enum

两个用于自定义的方式:

  • type
  • interface

注意

在JS中的这些内置函数:Number,String, Boolean,用于创建对应的包装对象,在日常开发中很少使用,故在TS也是同样的道理,所以在TS中进行类型声明时,通常都是使用小写的number,string,boolean。

例如:

let str1:string

str1 = 'hello'

str1 = new String ('hello')//这就会报错,因为类型其实不一样



let str2 :String

str2 = 'hello'

str2 = new String('hello')//不会报错

简单来说就是原始类型包装对象的差别

原始类型:

如number,string,boolean,在JS中是简单数据类型,在内存中占空间少,处理速度块

包装对象:

如Number对象,String对象,Boolean对象,是复杂类型,在内存中占用更多的空间,在日常开发中也很少由开发人员自己创建包装对象

常用类型与语法

1. any

含义是:任意类型,一旦将变量限制为any,就意味着放弃了对该变量的类型检查

// 明确的表示a的类型是 any —— 【显式的any】

let a: any

// 以下对a的赋值,均⽆警告

a = 100

a = '你好'

a = false

// 没有明确的表示b的类型是any,但TS主动推断出来b是any —— 隐式的any

let b

//以下对b的赋值,均⽆警告

b = 100

b = '你好'

b = false

注意点:any类型的变量可以赋值给任意类型的变量

/* 注意点:any类型的变量,可以赋值给任意类型的变量 */

let c:any

c = 9

let x: string

x = c // ⽆警告

2.unknown

含义是:未知类型,适用于:起初不确定数据的具体类型,要后期才能确定

  • 可以理解为一个类型安全的any

    // 设置a的类型为unknown
    
    let a: unknown
    
    //以下对a的赋值,均符合规范
    
    a = 100
    
    a = false
    
    a = '你好'
    
    // 设置x的数据类型为string
    
    let x: string
    
    x = a //警告:不能将类型“unknown”分配给类型“string“
    
  • 会强制开发者在使用前进行类型检查(三种方式:类型判断 + 两种断言方式),从而提供更强的类型安全

    // 设置a的类型为unknown
    
    let a: unknown
    
    a = 'hello'
    
    //第⼀种⽅式:加类型判断
    
    if(typeof a === 'string'){
    
     x = a
    
     console.log(x)
    
    }
    
    //第⼆种⽅式:加断⾔
    
    x = a as string
    
    //第三种⽅式:加断⾔
    
    x = <string>a
    
  • 读取any类型数据的任何属性都不会报错,而unknown完全相反(只要没进行检查包报警告的)

    let str1: string
    
    str1 = 'hello'
    
    str1.toUpperCase() //⽆警告
    
    let str2: any
    
    str2 = 'hello'
    
    str2.toUpperCase() //⽆警告
    
    let str3: unknown
    
    str3 = 'hello';
    
    str3.toUpperCase() //警告:“str3”的类型为“未知”
    
    // 使⽤断⾔强制指定str3的类型为string
    
    (str3 as string).toUpperCase() //⽆警告
    

3.never

含义是:任何值都不是,比如:undefined,null,'',0都不行

  • 几乎不用never去直接限制变量,因为没有什么意义,例如

    /* 指定a的类型为never,那就意味着a以后不能存任何的数据了 */
    
    let a: never
    
    // 以下对a的所有赋值都会有警告
    
    a = 1
    
    a = true
    
    a = undefined
    
    a = null
    
  • never一般是TS主动推断出来的,例如

    // 指定a的类型为string
    
    let a: string
    
    // 给a设置⼀个值
    
    a = 'hello'
    
    if (typeof a === 'string') {
    
     console.log(a.toUpperCase())
    
    } else {
    
     console.log(a) // TypeScript会推断出此处的a是never,因为没有任何⼀个值符合此处的逻辑
    
    }
    
  • never也可以用于限制函数的返回值

    // 限制throwError函数不需要有任何返回值,任何值都不⾏,像undeifned、null都不⾏
    
    function throwError(str: string): never {
    
     throw new Error('程序异常退出:' + str)
    
    }
    

4.void

含义是:空,即函数不反悔任何值,调用者也不应依赖其返回值进行任何操作!

  • void通常用于函数返回值声明

    function logMessage(msg:string):void{
     console.log(msg)
    }
    logMessage('你好')
    

    注意:该代码没有编写return指定函数返回值,所以logMessage函数是没有显示返回值的,但会有一个隐式返回值,是undefined,虽然函数返回类型为void,但也是可以接受undefined的,简单记为:undefined是void可以接受的一种空

  • 以下写法均符合规范

    // ⽆警告
    function logMessage(msg:string):void{
     console.log(msg)
    }
    // ⽆警告
    function logMessage(msg:string):void{
     console.log(msg)
     return;
    }
    // ⽆警告
    function logMessage(msg:string):void{
     console.log(msg)
     return undefined
    }
    
  • 但是注意:限制函数返回值时,undefined和void还是有区别,因为:**返回值类型为void的函数,调用者不应依赖其返回值来进行任何操作!**对比下两段代码:

    function logMessage(msg:string):void{
     console.log(msg)
    }
    let result = logMessage('你好')
    if(result){ // 此⾏报错:⽆法测试 "void" 类型的表达式的真实性
     console.log('logMessage有返回值')
    }
    
    function logMessage(msg:string):undefined{
     console.log(msg)
    }
    let result = logMessage('你好')
    if(result){ // 此⾏⽆警告
     console.log('logMessage有返回值')
    }
    

    理解void与undefined

    1. void是一个广泛的概念,用来表达空,而undefined是这种”空“的具体体现实现
    2. 因此可以说undefined是void能够接受的一种”空“的状态
    3. 也可以理解为:void包含undefined,但void所表达的语义超越了undefined,void是一种意图上的约定,而不仅仅是特定值的限制

5.oject

关于object(小写)Object(大写),直接说结论:实际开发中用的相对较少,因为范围太广了。

前端
TypeScript
$ cd ..