什么是TS?
我们在前端开发技术栈中总会听说ts,究竟什么是ts,ts相对于js有什么好处,今天总结一下
TS简介
ts不是去替换js 而是js的超集 在js的基础上进行扩展,我们说js是弱类型语言,声明变量不区分类型,可以直接进行赋值
let num = 10
let str = '我是一句字符串'
而在js使用中,我们可以将num赋值为字符串,将str赋值为数字,这样的形式在js中是没有问题的,也不会报错的,恰恰是因为js的这一特性,导致我们在大量编码的时候尤其是函数调用时,经常因为类型的问题报错,而且报错对应的位置不是错误发生的位置
而在引用ts之后,我们在声明变量的时候需要给变量添加类型,如果类型和值没有对应上就会有错误提示
同时呢,ts也支持es新特性,针对不同的场景有相应的配置
TS开发环境搭建
安装node.js
使用npm i -g typescript
创建一个ts文件
命令行输入tsc 回车 显示提示 就是安装成功
如上图所示
在编写好ts文件要编译时,使用 tsc 进行编译
新建一个ts 文件 输入console.log(''hello TS")
在命令行中对ts 文件进行编译 tsc + 文件名.ts 会生成一个js文件 就是编译成功
类型声明简介
声明一个变量a 类型是number
a的类型设置为number 以后a的类型只能是number
如果变量的声明和赋值是同时进行的 TS可以自动对变量进行类型检测
let c = false
规定函数的入参类型是number 返回值也是number
function sum(a:number,b:number):number{
return a+b
}
const result = sum(123,456)
字面量
字面量类型就是我将sex的可选类型设置为 male或famale
通过字面量设置sex的类型
同时使用 | 将其连接 这样就是一个字面量联合类型
//可以使用竖线来连接多个类型(联合类型)
let sex:"male" |"famale"
sex = 'male'
sex = 'famale'
let f:boolean| string
f= true
f = '测试'
any
//any
//声明变量如果不指定类型 变量类型就是any 隐式any
//直接设置any 就是显式any
let g:any
g = '123'
g = 123
g = true
unknown
表示未知类型的值,unknown实际上就是一个类型安全的any
但是将unknow类型的值赋值给已知类型会有错误
不能将未知类型赋值给已知类型
类型断言
可以用来告诉解析器变量的实际类型
类型断言就是 我知道类型是什么,给这个变量规定这个类型
let h = e as string
h = <string>e
/*
* 变量 as 类型
* <类型>变量
*/
void和never
void和never一般设置函数返回值的类型
如果函数没有返回值 就是void
void可以是null undefined
但是never不能有值 表示永远不会返回结果
object类型
声明一个对象b 里面有一个name属性,属性的类型是string
{}用来指定对象中可以包含哪些属性
语法 {属性名:属性值,属性名:属性值}
属性名后面加? 表示属性是可选的
let b:{name:string,age?:number}
b = {name:"孙悟空"}
如果规定对象c中有且仅有一个属性name 想要添加任意属性
[:string]:any 表示任意类型的属性
let c:{name:string,[propName:string]:any}
c = {name:'猪八戒',sex:'男'}
函数类型
设置函数结构的类型声明
语法 (形参1:类型,形参2:类型)=>返回值类型
let d:(num1:number,num2:number)=>number
d = function(num1,num2){
return num1+num2
}
array类型
声明一个字符串数组 希望数组中存储的都是字符串
let arrStr:string[]
arrStr = ['1','2']
或
let arrStr:Array<string>
arrStr = ['1','2']
声明一个数字数组 希望数组中存储的是数字类型
let arrNum:number[]
arrNum = [1,2,3,4,5,6]
或
let arrNum:Array<number>
arrNum = [1,2,3,4,5,6]
元组
元组就是固定长度的数组
声明一个数组 有两个元素 元素类型是string
[类型,类型]
let tupleStr:[string,string]
tupleStr = ['name','age']
枚举
把所有的可能情况都列出来,结果在多个值之间进行选择的时候,适合用枚举
//枚举
enum gender{
male = 0,
famale = 1
}
let objGender:{name:string,gender:gender}
objGender = {
name:'沙和尚',
gender:gender.male
}
判断
if(objGender.gender===gender.male){
console.log('男')
}else{
console.log('女')
}
类型的别名
相当于给类型起一个名字,例如类型的名字很长,我们起一个别名,简洁一些
type myType = string
let testStr:myType
接口
接口就是用来定义一个类的结构
interface
他规定了一个类中应该包含那些属性和方法
同时 接口也可以当成类型声明去使用
/* 通过接口定义 */
interface People{
name:string
age:number
gender:Gender
}
const obj:People = {
name:'小明',
age:18,
gender:Gender.male
}
相比之下 和通过类型声明很相似,但是类型声明的话 重复声明会有报错,但是针对接口 我们重复声明同名接口 不会报错 使用时将二者 合二为一来使用
接口中的所有属性都不能有实际的值
接口只定义对象的结构 不考虑实际的值
定义一个类 可以使类去实现接口
实现类就是满足接口的要求
implements 关键字
接口对类是一个限制
interface myInterface{
name:string
age:number
gender:Gender
}
class myClass implements myInterface{
name:string
age:number
gender:Gender
constructor(name:string,age:number,gender:Gender){
this.name = name
this.age = age
this.gender = gender
}
}
const myClassObj = new myClass('小明',18,Gender.male)
console.log(myClassObj,'myClassObj')
泛型
在定义函数或者类时, 遇到类型不明确的就可以使用泛型
在类型不明确是通过一个变量来代替 是使用的时候可以类型推断来确定类型
或者通过手动义泛型来指定泛型的类型
function Fn2<T>(a:T):T{
return a
}
/* 可以直接调用具有泛型的函数 */
let num1 = Fn2(123)
/* 手动指定泛型的类型是number */
let num2 = Fn2<number>(123)
let num3 = Fn2<string>('测试')
泛型可以同时指定多个类型
function Fn3<T,K>(a:T,b:K):T{
console.log(b)
return a
}
let num4 = Fn3<number,string>(1212,'测试')
限制泛型的范围
泛型T 必须是inter的实现类
也就是说在定义完Fn4这个函数时,我们调用函数,入参的参数必须得有length这个属性
interface Inter{
length:number
}
function Fn4<T extends Inter>(a:T):number{
return a.length
}
Fn4('123')
Fn4({length:10})
Fn4([1,2,3])
以上是我个人对TS的基本使用的看法,欢迎大家评论留言,交流心得