TypeScript学习(持续补充...)
简介
- 由微软开发,是基于JS的一个扩展语言
- 包含JS所有内容,即TS是JS的超集
- TS增加了:静态类型检查,接口,泛型等很多现代开发特性,更加适合大型项目的开发
- TS需要编译为JS,然后交给浏览器或其他JS运行环境执行
为何引入TS
简单来说,就是JS出现的太早,而现在用的地方很多,逐渐出现了很多的困扰。而目前需要想办法解决或者避免这些问题。比如:
- 不清楚的数据类型
- 有漏洞的逻辑
- 访问不存在的属性
- 低级的拼写错误
于是引出TS的核心:【静态类型检查】
静态类型检查是指在代码运行前进行检查,以发现代码的错误和不合理的地方,减小运行时出现异常的几率。(把运行时的错误前置)
显然要实现这些,TS的代码量肯定会多余JS,但TS结构会更加清晰,在后期的维护中TS也更优于JS。
编译TS
由于浏览器不能直接运行TS代码,需要编译为JS再交由浏览器解析器执行。
1.命令行编译
配置TS的编译环境,步骤:
-
创建ts文件,比如demo.ts
-
全局安装TypeScript
npm i typescript -g
-
使用命令编译.ts文件
tsc demo.ts
2.自动化编译
-
创建TS编译控制文件
tsc --init
(1)工程中会生成一个tsconfig.json配置文件,其中包含很多编译时的配置
(2)观察发现,默认编译的JS版本是ES7,我们可以手动调整为其他版本
-
监视目录中的.ts文件变化
tsc --watch 或者 tsc -w
-
小优化,当编译错误时不生成.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
- void是一个广泛的概念,用来表达空,而undefined是这种”空“的具体体现实现
- 因此可以说undefined是void能够接受的一种”空“的状态
- 也可以理解为:void包含undefined,但void所表达的语义超越了undefined,void是一种意图上的约定,而不仅仅是特定值的限制
5.oject
关于object(小写)与Object(大写),直接说结论:实际开发中用的相对较少,因为范围太广了。