TypeScript语法细节
联合类型(满足其中一个即可)
- 可以使用多种运算符,从现有的类型中构建新类型
const number|string = 123
- 可以是这些类型中的任何值
- 但是使用的时候需要小心
let virable: number | string = 123
function getData(id: number | string) {
//若我们想使用length方法,需要使用类型缩小
//直接使用会报错
// console.log(id.length)
if (typeof id === "string") {
console.log(id.length)
} else {
console.log(id);
}
}
类型别名
- 在 TypeScript中我们可以给类型起别名
- 主要是方便代码的阅读以及联合类型的复用
type IDtype = number | string
function getData(id:IDtype) {
//若我们想使用length方法,需要使用类型缩小
//直接使用会报错
// console.log(id.length)
if (typeof id === "string") {
console.log(id.length)
} else {
console.log(id);
}
}
接口声明
- 在 TypeScript中可以使用interface,对对象类型进行取别名
//采用声明式命名
interface IPerson {
name: string,
age:number
}
- 在大部分情况下,type与interface是没有区别的,实现的功能是一样的
type与interface的区别
- 一是type可以对应多种类型,而interface只能针对于对象类型
- 二是type不能对同一别名重复声明,而interface可以
- interface重复声明一个别名,可以将其进行合并
- 三是interface具有继承性,方便了代码后期的拓展
// * 一是type可以对应多种类型,而interface只能针对于对象类型
type numberType = number
type ObjType = { x: string }
interface IObj { x: string }
// * 二是type不能对同一别名重复声明,而interface可以
// * interface重复声明一个别名,可以将其进行合并
interface IObj { y: number }//需要满足x以及y
// * 三是interface具有继承性,方便了代码后期的拓展
interface IObjZ extends IObj {
//需要满足x以及y
z:boolean
}
- 总结,在实际开发中,对象类型使用interface,其他类型使用type即可
交叉类型(多种类型要同时满足)
- 通常是针对于对象类型进行的
- 若是普通类型的使用交叉类型,则会自动推断出是never类型
type myType = number & string
//通常不会这样操作
- 现在有两个对象类型,需要同时满足
interface IObj1 {
name: string
age:number
}
interface IObj2{
walk:()=>void
}
type IObj1IObj2 = IObj1&IObj2
//类型注解的时候可以使用IObj1IObj2,与下面的代码一致
const myObj: IObj1 & IObj2 = {
name: "zhangcheng",
age: 18,
walk() {
console.log("walk");
}
}
类型断言as
-
通常用在获取元素节点的时候
-
获取元素节点的时候,若根据标签获取 TS会根据标签推断出生成的是什么类型,可以做后续操作
-
但是若使用 id或者class进行获取,则不会推断出是什么类型,后续的操作也不能正常进行
const imEle = document.querySelector("div")
//可以直接进行对应类型的操作
const imEle = document.querySelector(".myDiv")
//可以进行指定
const imEle = document.querySelector(".myDiv") as HTMLDivElement
- 对于普通类型的也可以进行类型断言
- 一般是由确定的类型转成不太确定的类型
- 或者由宽泛的类型,转成确定的类型
- 注意不能对类型强制类型转换
let str: string = "123" as any
let myAny:any = 123 as number
非空类型断言
- 对标识符后面加!进行非空类型断言
- 在上述的学习中,我们知道,有些标识符是可有可无的
- 对于可有可无的标识符,我们在确保一定存在的情况下,就可以使用非空类型断言
function foo(message?: string) {
//直接使用会报错,因为message有可能没有
// console.log(message.length);
//解决方案一,使用可选链
console.log(message?.length)
//解决方案二:非空类型断言,在message一定存在的情况下
console.log(message!.length)
}
字面量类型
- 当我们使用const声明一个变量的时候,会用后面的值当作一个类型,即为 字面量类型
- 但是单纯的这样写字面量类型,是没有意义的
- 通常用于 类似于枚举的用途
type requestType = "GET" | "POST"
function request(url: string, method: requestType) {
//这样method只能取GET或者POST
}
request("http://xxx","GET")
- 但是若是以下情况,则不能直接传值
- 我们将要传入的信息用对象包裹
type requestType = "GET" | "POST"
function request(url: string, method: requestType) {
//这样method只能取GET或者POST
}
let info = {
url: "http://xxxx",
method:"GET"
}
//这样直接传会报错,因为info.method是string类型,而函数参数是requestType类型
// request(info.url,info.method)
//解决方案一
//使用类型断言
request(info.url, info.method as "GET")
//解决方案二
//使用字面量推理
let info2 = {
url: "http://xxxx",//url的类型"http://xxxx"
method:"GET"//method的类型"GET"
} as const
request(info2.url,info2.method)
类型缩小
- 目的是让一个类型,缩小到一个更加准确的范围
- 而与类型缩小一同使用的就是 类型保护
- 类型保护的方法通常有以下方法
- typeof
- === !==
- instanceof
- in
//typeof
type messageType = string | number
function getDataId(id: messageType) {
//id有可能是string类型或者,number类型
if (typeof id === "string") {
//判断条件就是类型保护,只有在string类型状态下,才会做如下操作
console.log(id.split(" "))
}
}
//===/!==通常用在判断字面量类型上
type requestType = "GET" | "POST"
function request(method: requestType) {
//method有可能是GET或者POST
if (method === "GET") {
//当method为GET的时候,执行的操作
} else {
}
}
//instanceof
function formate(date: string | Date) {
//时间的格式化,用于可能传入string或者Date对象
if (date instanceof Date) {
//判断date是否是Date实例出来的
}
}
//in,通常用于判断传入的对象中有没有某个属性
type userInfoType = {name:string,age:number}
let userInfo:userInfoType = { name: "zhangcheng", age: 18 }
function changeUserInfo(userInfo:userInfoType) {
//判断userInfo中是否有name属性
if ("name" in userInfo) {
console.log(userInfo.name);
}
}
TypeScript函数的类型
- 在 TypeScript中,函数参数有类型,函数的返回值有类型
- 而函数本身也有类型
- 通过函数类型表达式进行声明
//type fnType = (参数:参数类型)=>返回值类型
type fnType = (num1: number,num2:number) => number
//在一个函数中传入另外一个函数
//对这个函数进行类型指定
function numberSum(fn: fnType) {
console.log(fn(10,20))
}
numberSum(function (num,num1) {
return num+num1
})
- 通过函数调用签名的方式进行声明
- 因为函数本身是一个对象
- 若想将函数作为一个对象,且使用其中的属性,就可以使用调用签名的方法
interface Ifn {
name: string
age: number
//以下就是函数调用签名,代表这个对象可以被调用
(num1:number,num2:number):number
}
function calc(fn: Ifn) {
console.log(fn.name,fn.age);
fn(10,20)
}
function sum(num1:number,num2:number) {
return num1+num2
}
sum.name = "123"
sum.age = 18
calc(sum)
- 构造签名
- 是指函数可以通过 new方法进行调用
class Person{
}
interface ICONPerson {
//构造签名
new () : Person
}
function factory(fn: ICONPerson) {
return new fn()
}
参数的可选类型
- 在函数的参数中,有些参数是可以传可以不传的,那么我们可以将这个参数设置为可选参数
- 参数设置为可选参数,其类型就是 指定的类型 | undefined的联合类型
- 其中y就是可选类型
- 一般可选类型都是设置在最后
function sum(x:number,y?:number){}
参数的默认值
- 我们可以给函数的参数设置默认值
- 设置默认值的参数,在实际调用中,可以不用传参
- 设置默认值的参数,可以不用标明类型注解
- 同时该参数可以接收 undefined
function sum(x:number,y=100){}
剩余参数
- 我们可以使用…的方式接收传递进来的剩余参数
function sum(...arr: (string | number)[]) {
console.log(arr);
}
函数的重载(了解)
- 现在有一个需求
- 有一个sum函数,接收两个参数
- 这两个参数可能是number类型或者string类型
- 返回两个参数相加的值
- 注意:联合类型是不能使用+运算符的
//函数重载
function sum(num1: number, num2: number)
function sum(num1:string,num2:string)
//通用函数,是不能直接被调用的
function sum(num1, num2) {
return num1+num2
}
console.log(sum(10, 20));
console.log(sum("10", "20"));
//会报错
// console.log(sum(10,"20"));
可推导的this类型
- 目前在vue3以及react的项目中,其实很少再用到this了
- 但是我们还是应该了解以下this的类型
- 在没有特殊配置的情况下,TS中的this类型就是any类型
let obj = {
name: "zhangcheng",
sport() {
console.log(this);
}
}
function sum() {
console.log(this);
}
-
我们可以通过
tsc --init
初始化TS的配置,会生成一个 tsconfig.json的文件 -
若 noImplicitThis配置项为true,将不会允许模糊的this出现
- 但是this会通过上下文进行推导,推导成功的则正常使用(对象obj中的this)
- 没有推导成功的,则编译不通过(sum函数中的this)
-
同时,我们可以给 sum函数指定this
//第一个参数为指定this类型的参数,这是固定位置,且名称不能变
//后续的参数才是参数
function sum(this:{name:string},arg:number) {
console.log(this);
}
//只能通过call,bind,apply调用
sum.call({name:"zhangcheng"},10)
this相关的内置工具
- ThisParameterType和OmitThisParameter
function sum(this: { name: string }, num: number) { }
//提取函数中的this类型
type sumThis = ThisParameterType<typeof sum>
//剔除this,其余参数的类型
type argType = OmitThisParameter<typeof sum>
- ThisType工具,主要是将上下文的this绑定到某一个类型身上
- pinia内部实际上用了这个方法,这只是一个简易版本,运行将会是undefined
interface IState{
stateName:string
}
interface IStore {
state: IState
getData:()=>void
}
//这里的this类型,将会是IState类型
let store: IStore & ThisType<IState> = {
state: { stateName: "lisi" },
getData() {
//因此可以直接通过this.stateName访问state中的变量
console.log(this.stateName);
}
}