Typescript高级: 深入理解断言

深入理解 TypeScript 中的类型断言(Type Assertion) 类型断言是 TypeScript 中一个强大而独特的特性,它允许开发者告诉编译器:"我知道这个值的类型是什么,请相信我"。本文将全面探讨类型断言的概念、语法、使用场景、最佳实践以及潜在陷阱,帮助你在 TypeScript 开发中更有效地使用这一特性。 阅读详情

概述

  • 关于断言,就是TS 类型断言,即把两种能有重叠关系的数据类型进行相互转换的一种 TS 语法
  • 把其中的一种数据类型转换成另外一种数据类型
  • 类型断言和类型转换产生的效果一样,但语法格式不同
  • TS 类型断言语法格式:A 数据类型的变量 as B 数据类型
  • 注意:A 数据类型和 B 数据类型必须具有重叠关系

关于重叠关系的几种场景


1 ) 如果 A,B 是类并且有继承关系

  • 这里,存在 extends 关系,无论 A,B 谁是父类或子类
  • A 的对象变量可以断言成 B 类型,B 的对象变量可以断言成A类型
  • 但注意一般在绝大多数场景下都是把父类的对象变量断言成子类
class People {
  public myusername!: string;
  public myage!: number;
  public address!: string
  public phone?: string
  constructor() {}
  eat() {}
  step() {
    console.log("People=>step");
  }
}

class Stu extends People {
  public username!: string
  public age!: number;
  public address!: string

  constructor(username: string, age: number, address: string, public phone: string) {
    super();
    this.address = address;
  }
  study() {}
}

function test1() {
  const stu = new Stu("wangwu", 23, "北京", "123")
  const result = stu as People; // 正确 这是断言
  // const result = <People>stu; // 正确 这是类型转化
  result.step() // 可正常调用 验证了可以调用父类的方法
}

function test2() {
  const people = new People()
  // const result = people as Stu; // 类型断言 正确
  const result = <Stu>people;// 类型转换 正确
  // result.step(); // 正常输出 可以正常调用父类自己的方法
  result.study(); // 错误,不可以调用 Stu 的方法
}

// test1()
// test2()
  • 两个类之间断言的规则, 两个类中任意一个的属性和方法是另一个类的属性和方法完全相同或子集
  • 则这两个类可以相互断言, 否则这两个类就不能相互断言
  • 注意,上述,即使可以相互断言,但是也无法调用两者不相同的方法

2 ) 如果 A,B 是类,但没有继承关系

  • 两个类中的任意一个类的所有的 public 实例属性【不包括静态属性】, 加上所有的 public 实例方法
  • 和另一个类的所有 public 实例属性加上所有的public 实例方法完全相同或是另外一个类的子集
  • 则这两个类可以相互断言, 否则这两个类就不能相互断言
class People {
  constructor(public username: string, public age: number, public address: string) {}
  study() { console.log('People study')} // 这个可以注释掉看下
}

class Stu {
  public  username!: string
  public age!: number;
  public address!: string
  public phone!:string;
  constructor(username: string, age: number, address: string) {
    this.address = address;
  }
  public study() { console.log('Stu study') }
}

function test1() {
  const people = new People("wangwu", 23, "beijing")
  // const result = people as Stu; // 可以正确断言
  const result = <Stu>people; // 可以正确转换
  result.study(); // 正确调用,输出 People study
}

function test2() {
  const stu = new Stu("wangwu", 23, "北京")
  stu.study() // 可以正常调用
  const result = stu as People; // 正确断言
  // const result = <People>stu; // 正确转换
  result.study() // 正确调用,与上面输出一致,注意,这里并不是调用 People 中的study
}

// test1()
// test2()

3 ) 如果 A 是类,B 是接口,并且 A 类实现了 B 接口【implements】

  • 符合以上条件,则 A 的对象变量可以断言成 B 接口类型
  • 同样 B 接口类型的对象变量也可以断言成A类型
interface People {
  username: string, age: number, address: string, phone: string
}

class Stu implements People {
  public username!: string
  public age!: number
  public address!: string
  public phone!: string
  public kk() {}
  get value() {
    return this.username
  }
  set value(newVal) {
    this.username = newVal
  }
  constructor(username: string, age: number, address: string) {
    this.address = address;
  }
}

function test1() {
  const people: People = { username: "wangwu", age: 23, address: "11", phone: "111" }
  const result = people as Stu; // 断言 正确
  const result2 = <Stu>people;// 类型转换 正确
}

function test2() {
  const stu = new Stu("wangwu", 23, "北京")
  const result = stu as People; // 断言 正确
  const result2 = <People>stu // 类型转化 正确
}

test1()
test2()

4 )如果 A 是类,B 是接口,并且 A 类没有实现 B 接口

  • 符合上述场景,则断言关系和场景2的规则完全相同
interface People {
  username: string, age: number, address: string, phone: string
}

class Stu {
  public username!: string
  public age!: number;
  public address!: string
  public phone!: string
  public kk() {}

  get value() {
    return this.username
  }

  set value(newVal) {
    this.username = newVal
  }
  constructor(username: string, age: number, address: string) {
    this.address = address;
  }
}

function test1() {
  const people: People = { username: "wangwu", age: 23, address: "11", phone: "111" }
  const result = people as Stu; // 断言正确
}

function test2() {
  const stu = new Stu("wangwu", 23, "北京")
  stu as People; // 断言正确
}

test1()
test2()

5 )如果 A 是类,B 是 type 定义的数据类型

  • B 就是引用数据类型, 例如 Array 对象 (不能是基本数据类型,例如 string,number, boolean)
  • 并且有 A 类实现了 B type 定义的数据类型 implements
  • 则 A 的对象变量可以断言成 B type 定义的对象数据类型
  • 同样 B type 定义的对象数据类型的对象变量也可以断言成 A 类型
type People = {
  username: string, age: number, address: string, phone: string
}

class Stu implements People {
  public username!: string
  public age!: number;
  public address!: string// 类型 "Stu" 中缺少属性 "address",但类型 "typestu2" 中需要该属性。t
  public phone!: string
  get value() {
    return this.username
  }

  set value(newVal) {
    this.username = newVal
  }

  constructor(username: string, age: number, address: string) {
    this.address = address;
  }
}

function test1() {
  const people: People = { username: "wangwu", age: 23, address: "11", phone: "111" }
  people as Stu; // 断言正确
}

function test2() {
  const stu = new Stu("wangwu", 23, "北京")
  stu as People; // 断言正确
}

test1()
test2()

6 ) 如果 A 是类,B 是 type 定义的数据类型,并且 A 类没有实现 B type定义的数据类型

  • 如果符合上述场景,则断言关系和第2种场景的规则完全相同
type People = {
  username: string, age: number, address: string, phone: string
}

class Stu {
  public username!: string
  public age!: number
  public address!: string
  get value() {
    return this.username
  }

  set value(newVal) {
    this.username = newVal
  }
  constructor(username: string, age: number, address: string) {
    this.address = address;
  }
}

function test1() {
  const people: People = { username: "wangwu", age: 23, address: "11", phone: "111" }
  // const result = people as Stu; // 报错:类型 "People" 到类型 "Stu" 的转换可能是错误的,因为两种类型不能充分重叠。如果这是有意的,请先将表达式转换为 "unknown"。类型 "People" 中缺少属性 "value",但类型 "Stu" 中需要该属性
}

function test2() {
  const stu = new Stu("wangwu", 23, "北京")
  // stu as People; // 报错:类型 "Stu" 到类型 "People" 的转换可能是错误的,因为两种类型不能充分重叠。如果这是有意的,请先将表达式转换为 "unknown"。 类型 "Stu" 中缺少属性 "phone",但类型 "People" 中需要该属性。
}

test1()
test2()

7 ) 如果 A 是一个函数上参数变量的联合类型,例如 string | number

  • 如果符合上述条件,那么在函数内部可以断言成 string 或number 类型
function selfMutiply(one: string | number) {
    // one as number +3;
}

8 )多个类组成的联合类型的断言

  • 例如:const vechile: Car | Bus | Trunck
  • vechile 可以断言成其中任意一种数据类型
  • 例如 vechile as Car, vechile as Bus , vechile as Trunck
class Car {
  public name: string
}

class Bus {
  public color: string
}

class Trunck {
  public weight: number
}


let vechile: Car | Bus | Trunck // 注意,这里是 let, 使用 const 必须初始化
const x = vechile as Car // 断言正确
const y = vechile as Bus // 断言正确
const z = vechile as Trunck // 断言正确

9 )any 或 unknown 类型

  • 任何数据类型都可以转换成 any 或 unknown 类型
  • any 或 unknown 类型也可以转换成任何其他数据类型
function testAny(one: string | number, two: string | number) {
  return one as any + two as any
}

function testUnknow(one: string | number, two: string | number) {
  one as unknown
  two as unknown
  console.log(one)
  console.log(two)
}

console.log(testAny(3, 5)) // 8
console.log(testAny("3", 5)) // 35


testUnknow(1, "5") // 1 5

10 ) Symbol 中的断言

  • Symbol 可以直接作为对象的索引
  • Symbol 类型也可以断言为 any 进行访问
  • Symbol 类型不可以断言为 unknown 来访问
const symid = Symbol("objid") // 定义一个 Symbol
const obj = { [symid]: 101, username: "wangwu", age: 23 } // 
const username = obj["username"]
const objid = obj[symid] // 这个可以访问
console.log(objid) // 101

const objid1 = obj[symid as any] // 这个也可以
console.log(objid1) // 101

// const objid2 = obj[symid as unknown] // 这个是错误的,直接会报错 类型“unknown”不能作为索引类型使用
【TypeScript入坑】TypeScript 的复杂类型「Interface 接口、class类、Enum枚举、Generics泛型、类型断言」 【TypeScript入坑】TypeScript 的复杂类型「Interface 接口、class类、Enum枚举、Generics泛型、类型断言、namespace」 阅读详情

相关推荐

TypeScript详解(安装使用、基础类型总结、类型断言用法、接口、类、函数、泛型、相同类型之间赋值、unknown、枚举等)

TypeScript概念 是 JavaScript 的一个超集,它可以编译成纯JavaScript,也可以在任何浏览器操作系统运行。简单来说就是JS的一个升级版本,给JS加了限制规范(接口等),也扩展了JS(类等)的能力 基础类型 注意和JS不同,JS区分基础类型和复杂数据类型,TS不区分,即基础类型就是数据类型,它包括JS中的6中数据类型(undefined、null、boolean、number、string、object),不包含symbol。除此之外还包含函数、数组、元祖、枚举、任意值(.

AIWWY的博客 2477

TS类型断言

TypeScript中的类型断言是一种将变量或表达式的类型强制转换为开发者指定的类型的方式。可以使用尖括号(<>)语法或者as语法进行类型断言。使用as语法的类型断言:这里,我们将一个any类型的变量str断言为string类型,并使用它的length属性获取字符串的长度。

weixin_42560424的博客 6896

24、TS中的类型断言

上面的例子中,我们也可以通过[扩展 window 的类型(TODO)][]解决这个错误,不过如果只是临时的增加 foo 属性,as any 会更加方便。总之,一方面不能滥用 as any,另一方面也不要完全否定它的作用,

imkaifan的博客 955

【进阶】TS 中的 类型断言 和 泛型

本章内容包含: 1、类型断言,2、非空断言,3、typeof,4、keyof,5、泛型,6、泛型函数,7、泛型的问题,8、泛型接口,9、泛型工具

jiang_ziY的博客 1万+

深入理解TypeScript中的断言函数与类型断言

TypeScript中断言函数和类型断言的区别:断言函数通过控制流分析确保类型安全,会在运行时验证类型,失败时抛出异常;而类型断言仅是开发者对类型的假设,没有运行时保证。断言函数更强大可靠,能精确控制类型,而类型断言只是临时类型转换。实际开发中应优先使用断言函数来提高代码安全性。

m0_74337424的博客 47

深入理解TypeScript非空断言操作符!

非空断言操作符(!)用于告诉TypeScript编译器,某个变量在运行时不可能为null或undefined。这在编译器无法确定变量非空的情况下非常有用。

m0_62153576的博客 583

TS:类型断言

类型断言好比其他语言中的类型转换,但是不是真正的类型转换方式,之所以不被称为类型转换,是因为转换通常意味着某种运行时的支持。但是,类型断言纯粹是一个编译时语法,同时,它也是一种为编译器提供关于如何分析代码的方法。

小栗子的博客 2428

TypeScript中的const断言:深入理解与实践

断言在TypeScript中是一个非常有用的工具,它可以帮助我们更精确地控制变量和对象的类型推断,特别是在处理常量和不可变数据时。断言是一种强大的类型工具,它可以帮助开发者更精确地定义变量的类型,并提供更好的类型推断和代码可读性。断言是TypeScript 3.4版本引入的特性,主要作用是将变量的类型推断为其字面量类型,同时使变量具有。通过这些实践,我们可以更好地利用TypeScript的类型系统,编写更安全、更可维护的代码。断言在原始类型上的应用及其在对象类型中的特殊表现。在TypeScript中,

2501_90323865的博客 50

深入理解 TypeScript 高级用法

单独使用条件类型可能用处不是很大,但是结合泛型使用时就非常有用。一个常见的用例就是使用带有 never 类型的条件类型来修剪类型中的值。其中 NullableString​ 可以是 string​ 或 null​ 类型,它用于 itemName​ 变量。never : T;NonNullable​ 和 NoNull​ 之间的区别在于 NonNullable​ 将从类型中删除 undefined​ 以及 null。// 这里取一个[0, 10)范围内的随机值。

Jack, what else can you do besides holding your little darling? 1468

掌握TypeScript高级类型:断言签名与类型映射

本篇博客深入探讨TypeScript中的断言签名和类型映射技术。断言签名允许我们在不进行条件判断的情况下改变一个值的类型,而类型映射则用于通过索引访问扩展类型,并结合映射类型如Partial<T>处理复杂对象的属性。通过实际案例,我们将学习如何运用这些技术来提高代码的类型安全性,以及如何利用泛型、类型别名和声明合并等工具来优化TypeScript编程体验。

weixin_42400643的博客 747

深入理解TypeScript中的Callable与类型断言

本文深入探讨了TypeScript中Callable的用法以及类型断言的概念和应用。在Callable部分,我们学习了如何将函数定义为接口或类型的一部分,并且如何使用可选参数和重载。类型断言部分则详细解释了如何通过断言覆盖TypeScript的类型推断,以及在实际开发中需要注意的陷阱和最佳实践。

weixin_35752233的博客 490

『TypeScript』深入理解TypeScript基本类型及其应用

📣读完这篇文章里你能收获到:掌握TypeScript的基本及高级数据类型,掌握TypeScript的类型系统

老陈聊架构 1443

TypeScript中defineProperty与断言签名的高级用法

本文深入探讨了TypeScript中defineProperty属性描述符的复杂性和处理方式,以及TypeScript 3.7中引入的断言签名的实际应用。通过具体示例,展示了如何通过断言签名动态地改变参数或变量的类型,并探讨了自定义defineProperty函数的实现。文章旨在帮助读者理解和掌握TypeScript在类型系统方面的高级特性。

weixin_36173034的博客 492

Typescript高级: 深入理解Extract类型

在TypeScript这一逐渐成为前端开发首选的静态类型检查语言中,类型系统提供了丰富的工具来帮助开发者编写更加健壮和可维护的代码。其中,是一个强大的内置实用类型,用于从一个联合类型T中提取出属于另一个类型U的那些类型。本文将深入探讨Extract类型的工作原理、应用场景以及如何有效利用它来提升代码的类型安全性和表达力。Extract是一个条件类型,其定义为:从类型T中选取那些同时也可以被类型U赋值的类型简而言之,它像一个过滤器,保留了T中与U兼容的部分。

Wang的专栏 1420

深入理解TypeScript中的高级类型工具

本文将深入探讨TypeScript中的高级类型工具,包括如何从类型中剔除null和undefined,获取函数参数类型,构造元组类型,以及如何通过类型断言解决特定编程问题。通过丰富的代码示例和详细的解释,本文将帮助你更好地理解和运用TypeScript中的高级类型特性。

weixin_33481022的博客 485

深入理解TypeScript高级类型与模式

本文是对《TypeScript高级类型与模式》书籍中的一个章节内容的深入解析。文章探讨了TypeScript中复杂类型的使用,包括但不限于索引访问限制、联合类型、交叉类型、条件类型、泛型、类型断言等。通过详细的代码示例和实际应用案例,揭示了TypeScript在现代JavaScript开发中的强类型特性如何提升代码质量和可维护性。对于前端开发者和TypeScript学习者而言,本文将是一次对高级类型系统的深入洞察。

weixin_42497762的博客 422

掌握TypeScript的非空断言(!)和可选链(?):开发效率翻倍!

通过今天的学习,我们了解了如何在TypeScript中使用非空断言和可选链来提高代码的安全性和开发效率。

十一逐星的博客 1136

电商秒杀场景下,如何用Redis+Lua脚本实现原子性库存扣减(附完整代码)

本文针对电商秒杀场景下的高并发与超卖难题,详细解析了如何利用Redis的原子性命令与Lua脚本实现可靠的库存扣减。通过对比多种方案,阐述了Redis+Lua作为黄金搭档的技术原理,并提供了从基础扣减到预扣减模型的完整代码实现,确保在高并发下数据的一致性与系统性能。

weixin_29219539的博客 504

Typescript高级用法

typescipt高级用法

优快云zhaojiale的博客 783

全网最详细 解决戴维南定理的详细推导

替代定理,戴维南定理详细证明

m0_52555753的博客 3万+

CTF 命令执行绕过总结

tac:从最后一行开始显示,可以看出 tac 是 cat 的反向显示。或:rce-xor-or.php & rce-xor-or.py。# ls -t >shell 将输出输入到shell文件中。异或:rce-xor.php & rce-xor.py。%09(url传递)(cat%09flag.php)sh /flag 2>%261 //报错出文件内容。2、1使用空变量$*和$@,$x,${x}绕过。7、异或无符号(过滤0-9a-zA-Z)more:一页一页的显示档案内容。

jnszstmei的博客 1960
上一篇: K8s: Helm搭建mysql集群(2)
下一篇: Typescript高级: 深入理解const和readonly
Wang's Blog
博客等级 码龄12年 7433粉丝 2420原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wang's Blog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值