TS查漏补缺【类型守卫】

类型守卫与类型判断

为什么要用类型守卫?

类型守卫定义:在语句的块级作用域【if语句内或三目运算符表达式内】缩小变量的一种类型推断行为

类型守卫产生时机:TS条件语句中遇到下列条件关键字时,会在语句中的会计作用域内缩小变量的类型,这种类型推断的行为称作类型守卫(Tyoe Guard),类型守卫可以帮助我们在块级作用域缩小更为需要的精确的变量类型,从而减少不必要的类型断言。

  • 类型判断:typeof
  • 属性或者方法或者函数判断:in
  • 实例判断:instanceog
  • 字面量相等判判断:==,===,!=,!==

new 实例的底层发生了什么?

共分为三个步骤,参见如下栗子:

function Person (phone, age) {
  this.phone = phone
  this.age = age
  this.showOne = function () { }
}
Person.prototype.doEat = function () {
  console.log(this.phone);
}
let person = new Person("132", 23)
console.log(typeof person);

// new一个实例对象的三步

// 第一步:创建一个Object对象
// var obj = new Object();
var obj = {}

// 第二步:让新创建的对象的__proto__指向Person的原型对象空间
obj.__proto__ = Person.prototype

// 第三步:借用Person构造函数中的obj对象增加属性
Person.apply(obj, ["2123465", 18])
console.log(obj);

typeof有何局限性?如何解决?

typeof 作用:typeof用来检测一个变量或一个对象的数据类型。
typeof检测的范围:
typeof检测变量的类型范围包括: “string" | "number" / "bigint" / "boolean" | "symbol[ "undefined""obiect" "function”等数据类型。

typeof 的局限性
typeof检测变量并不完全准确,例如 typeof null结果为object,这其实设计者的一个bug,但后来一直没有被改过来,于是就此传下来了,但把 null当成 object 的理由说成是未来可能会拥有一个对象空间,这个理由很牵强【我们检测的是对象变量此刻的类型】,null 本来即是数据类型,也是值。所以typeof null直接显示null最合适了。
再例如:使用typeof来检测一个数组变量,typeof []结果显示的是object,从Array创建的本质上来说确实是object,正如我们在2-29-1中所讲,但开发者期待看到的是Array,这更符合预期。Array和我们定义的普通函数一样,具有双重性,当成函数类型时用来创建数组对象,但也是一个构造函数对象,拥有静态成员和prototype原型对象属性。【这一点我们在TS继承课题已经讲过】
再比如:使用typeof来检测一个Set变量,Map变量,结果显示的是依然是object.。
 

 typeof的替代方案
Object.prototype.toString.call
object.prototype.toString.call ([])展示

[ object Array ]object.prototype.toString.call(null)展示[ object null ]
object.prototype.toString.call(Set类型的变量)展示[ object Set ]object.prototype.toString.call(Map类型的变量)展示[ object Map ]

typeof 的替代方案依然无法解决的问题
就是无法获取一个自定义的类的实例变量或构造函数的对象变量的真正创建类型,答案是使用instanceof 来解

 instanceof格式:

对象变量instanceof 类名或函数名
instanceof 的主要作用: instanceof帮助我们准确的判断一种自定义函数或类创建的对象变量的数据类型。instanceof 执行后返回true的几种条件【符合一个即可】:
(1)对象变量.proto=类名或函数名.prototype。
解释1:如果instanceof 关键字左边对象变量的proto属性指向的原型对象空间=右边类名或函数名的prototype对象属性指向的原型对象空间,那么返回true。
(2)对象变量.proto.proto.._proto_=类名或函数名.prototype。
解释2: instanceof 左边对象变量proto的1到多个上一级proto指向的原型对象空间,等于右边类名或函数名的prototype对象属性指向的原型对象空间,那么也返回true,按照这个查找规律,会一直找到
Object.prototype对象属性指向的原型对象空间为止。

### 类型断言 类型断言是TypeScript中一种显式地告诉编译器某个值的实际类型的方式,它不会进行任何运行时的类型或转换,而仅仅是在编译时为变量提供一个类型注解,是一个编译时语法,旨在帮助开发者更好地利用TypeScript类型系统。当开发者比TypeScript更了解某个值的详细信息时,可使用类型断言告诉编译器如何理解这个值,它好比其他语言里的类型转换,但不进行特殊的数据检和解构,没有运行时的影响,只在编译阶段起作用[^3][^4][^5]。 类型断言有两种形式: - “尖括号” 语法: ```typescript let someValue: any = "this is a string"; let strLength: number = (<string>someValue).length; ``` - “as” 语法: ```typescript let someValue: any = "this is a string"; let strLength: number = (someValue as string).length; ``` ### 类型守卫 类型守卫用于在运行时检某个值的类型,从而缩小类型范围,增加代码的类型安全性和灵活性。常见的类型守卫方式有: - `typeof` 操作符进行类型守卫:用于区分原始数据类型,示例如下: ```typescript function printValue(value: string | number) { if (typeof value === 'string') { console.log(value.toUpperCase()); } else { console.log(value.toFixed(2)); } } ``` - `instanceof` 操作符进行类型守卫:用于类的类型判断,示例如下: ```typescript class Animal { makeSound() { console.log('Some sound'); } } class Dog extends Animal { bark() { console.log('Woof!'); } } function performAction(animal: Animal) { if (animal instanceof Dog) { animal.bark(); } else { animal.makeSound(); } } ``` ### 类型断言和类型守卫的区别 类型断言是编译时语法,仅在编译阶段起作用,不会改变变量的运行时值,只是告诉编译器如何理解这个值;而类型守卫是运行时检,用于在运行时确定某个值的类型,从而缩小类型范围,保证代码在运行时的类型安全性。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值