为何需要TypeScript
ts存在静态类型检查:在代码运行前进行检查,发现代码的错误或不合理之处,减少运行时异常的出现的几率,此种检查叫静态类型检查, TypeScript的核心就是静态类型检查,简言之就是把运行时的错误前置。
同样的功能,typescript的代码量要大于JavaScript,但由于typescript的代码结构更加清晰,在后期代码的维护中typescript却远胜于JavaScript
编译typescript
浏览器不能直接运行typescript代码,需要编译为JavaScript再交由浏览器解析器执行。
类型总览
JavaScript中的数据类型:
string、number、Boolean、null、undefined、bigint、symbol、object(array、function、date、error)
typescript中的数据类型:
- 上述所有JavaScript类型
- 六个新类型
- any
- unknown
- never
- void
- tuple元组
- enum枚举
- 两个用于自定义类型的方式
- type
- interface
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类型的变量,可以赋值给任意类型的变量
let c:any
c = 9
let x: string
x = c //无警告
unknown
含义:未知类型
- unknown可以理解为一个类型安全的any,适用于:不确定数据的具体类型
- unknown会强制开发者在使用之前进行类型检查,从而提供更强的类型安全性
- 读取any类型数据的任何属性都不会报错,而unknown正好与之相反
never
含义:任何值都不是,简言之就是不能有值,undefined、null、‘ ’、0都不行
- 几乎不用never去直接限制变量,因为没有意义
- never一般是typescript主动推断出来的
- never也可用于限制函数的返回值
void
void通常用于函数返回值声明,含义:【函数返回值为空,调用者也不应依赖其返回值进行任何操作】
function logMessage(msg:string):void{
console.log(msg)
return undefined //无警告
}
logMessage('你好')
注意:没有编写return去指定函数的返回值,所以logMessage函数是没有显式返回值的,但是会有一个隐式返回值,就是undefined;即:虽然函数返回类型为void,但也可以接受undefined。undefined是void可以接受的一种”空“
- 函数是可以返回undefined的,至于显示返回,还是隐式返回,都无所谓
- 函数调用者不应关心函数返回的值,也不应依赖返回值进行任何操作,即使返回了
声明函数类型
let count:(a:number,b:number)=> number
count = function(x,y){
return x+y
}
注意:1. typescript中的”=>“在函数类型声明时表示函数类型,描述其参数类型和返回类型
- JavaScript中的”=>“是一种定义函数的语法,是具体的函数体现
声明数组类型
let arr1: string[]
let arr2: Array<string>
arr1 = ['a','b','c']
arr2 = ['hello','world']
tuple
元组是一种特殊的数组类型,可以存储固定数量的元素,并且每个元素的类型是已知的且可以不同。元组用于精确描述一组值的类型,?表示可选元素
//第一个元素是string类型,第二个元素是number类型
let arr1:[string,number]
//第一个元素是number类型,第二个元素是可选的,如果存在,必须是Boolean类型
let arr2:[number,boolean?]
//第一个元素必须是number类型,后面的元素可以是任意数量的string类型
let arr3:[number,...string[]]
enum
-
数据枚举
是最常见的枚举类型,其成员的值会自动递增,且数字枚举还具备反向映射的特点,在下面代码的打印中,可以通过值来获取对应的枚举成员名称
enum Direction{ up, down, left, right } console.log(Direction) //打印Direction会看到如下内容 /* { 0:'up', 1:'down', 2:'left', 3:'right' } */ //反向映射 cosole.log(Direction.up) //0 cosole.log(Direction[0]) //up //此行代码报错,枚举中的属性是只读的 Direction.up = 'shang' function walk(n: Direction){ if(n === Direction.up) console.log("向上走") else if(n === Direction.down) console.log("向下走") else if(n === Direction.left) console.log("向左走") else if(n === Direction.right) console.log("向右走") } walk(Direction.up) walk(Direction.down) walk(Direction.left) walk(Direction.right)
-
常量枚举
是一种特殊枚举类型,使用const关键词定义,在编译时会被内联,避免生成一些额外的代码。即使用常量枚举的typescript代码编译后生成的JavaScript代码量较小。
const enum Direction{ up, down, left, right }
type
可以为任意类型创建别名,让代码更简洁、可读性更强
-
基本用法
type num = number; //num是类型别名 let price: num price = 100
-
联合类型(一种高级类型,表示一个值可以是几种不同类型之一)
type status = number|string type gender = '男'|'女' function printStatus(data:status):void{ console.log(data); } function printGender(data:gender):void{ console.log(data); } printStatus(404) printStatus('404') printGender('女')
-
交叉类型(允许将多个类型合并为一个类型,合并后的类型将拥有所有被合并类型的成员。交叉类型通常用于对象类型)
type area = { height:number width:number } type address = { num:number cell: number } type House = area & address const house:House = { height: 100, width:100, num:3, cell:78 }
interface和type的区别
相同点:interface和type都可以用于定义对象结构,两者在许多场景中是可以互换的
不同点:interface更专注于定义对象和类的结构,支持继承、合并;type可以定义类型别名、联合类型、交叉类型,但不支持集成和自动合并
interface和抽象类的区别
相同点:都用于定义一个类的格式
不同点:interface只能描述结构,不能有任何实现代码,一个类可以实现多个接口;抽象类:既可以包含抽象方法,也可以包含具体方法,一个类只能继承一个抽象类
泛型
泛型允许我们在定义函数、类或接口时,使用类型参数来表示未指定的类型,这些参数在具体使用时,才被指定具体的类型
function logData<T>(data:T):T{
console.log(data)
return data
}
logData<number>(100)
logData<string>('hello')
泛型可以有多个
function logData<T,U>(data1:T,data2:U):T | U{
return Date.now() % 2 ? data1:data2
}
logData<number,boolean>(100,true)
logData<string,number>('hello',666)