TypeScript(二):TypeScript的细节

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")
//可以直接进行对应类型的操作

image.png

const imEle = document.querySelector(".myDiv")
//可以进行指定
const imEle = document.querySelector(".myDiv") as HTMLDivElement

image.png

image.png

  • 对于普通类型的也可以进行类型断言
    • 一般是由确定的类型转成不太确定的类型
    • 或者由宽泛的类型,转成确定的类型
    • 注意不能对类型强制类型转换
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声明一个变量的时候,会用后面的值当作一个类型,即为 字面量类型

image.png

  • 但是单纯的这样写字面量类型,是没有意义的
  • 通常用于 类似于枚举的用途
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);
    }
}
  • 32
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值