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”不能作为索引类型使用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/603427.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

批量图片重命名及汇总

又一堆图片文件需要处理... 源文件分布&#xff1a; 有N个文件夹&#xff0c;每个文件夹下又有M个子文件夹&#xff0c;每个子文件夹下有X张图片。 例如文件夹A下有子文件夹A1,A2,A3&#xff0c;子文件夹A1下有图片a-1,a-2,a-3...... 处理目标&#xff1a; 1、将所有图片汇…

算法提高之树的中心

算法提高之树的中心 核心思想&#xff1a;树形dp 换根dp 每个点作为根节点 找其子树的最大距离和父节点的最大距离 dfs1&#xff1a;求子树对于当前根节点的最大距离和次大距离 求次大距离原因&#xff1a;如果当前节点是其父节点子树的最大路径上的点&#xff0c;最大距离不…

基于Linux中的 进程相关知识 综合讲解

目录 一、进程的基本概念 二、pid&#xff0c;ppid&#xff0c;fork函数 三、进程的状态讲解 四、进程的优先级 五、完结撒❀ 一、进程的基本概念 概念&#xff1a; ● 课本概念&#xff1a;程序的一个执行实例&#xff0c;正在执行的程序等 ● 内核观点&#xff1a;担当…

深度学习实例2_车牌识别分割——自学笔记

import cv2 from matplotlib import pyplot as plt import os import numpy as np from PIL import ImageFont, ImageDraw, Image彩色图片显示 def plt_show0(img):b,g,r = cv2.split(img)img = cv2.merge([r, g, b])plt.imshow(img)plt.show()灰度图片显示 def plt_show(img…

暗区突围PC测试资格获取 Twitch老鼠台一键领取测试资格教程

Twitch平台&#xff0c;这个广受欢迎的直播巨头&#xff0c;不仅是游戏文化的直播聚集地&#xff0c;还常与各类游戏携手合作&#xff0c;为观众带来独特的互动体验&#xff0c;观看直播即可解锁游戏内奖励。正值热门游戏《暗区突围》PC版测试阶段&#xff0c;Twitch再次发力&a…

Ai时代使用语音笔记整理文稿提高创作效率

其实传统的创作方式是用钢笔或者圆珠笔手写草稿。成稿后花钱誊抄数份邮寄给出版商。 计算机普及后&#xff0c;有人开始直接使用打字机或计算机创做&#xff0c;打字其实要比手写的速度快数倍&#xff0c;这样效率的提升&#xff0c;加上文创平台基本上都是按字数给收益&#…

去哪找高清视频素材?哪个网站有视频素材?

在这个视觉表达日益重要的时代&#xff0c;获取高品质的视频素材变得尤为关键。4K和无水印视频素材特别受到创作者的青睐&#xff0c;因为它们能极大地提升视觉作品的吸引力和专业度。接下来&#xff0c;我将介绍几个国内外的优秀视频素材网站&#xff0c;助您在创作旅程上一帆…

为什么现在越来越多的人会选择陪诊

现在越来越多的人选择陪诊的原因有多方面。 首先&#xff0c;随着人口老龄化、医疗资源分配不均等问题的日益突出&#xff0c;许多老年人和病患在就医过程中面临诸多困难&#xff0c;如挂号、排队、取药等繁琐的手续和流程。陪诊服务能够为他们提供极大的便利&#xff0c;帮助…

[初阶数据结构】单链表

前言 &#x1f4da;作者简介&#xff1a;爱编程的小马&#xff0c;正在学习C/C&#xff0c;Linux及MySQL。 &#x1f4da;本文收录于初阶数据结构系列&#xff0c;本专栏主要是针对时间、空间复杂度&#xff0c;顺序表和链表、栈和队列、二叉树以及各类排序算法&#xff0c;持…

添砖Java之路其三——自增自减运算符,数据转换与原码反码补码。

目录 运算符&#xff1a; 转换&#xff1a; 隐式转换&#xff1a; 小范围数据可以直接可以给大范围数据&#xff1a; 这里做了一张图范围向下兼容表​编辑 运算时&#xff0c;数据范围小的和数据范围大的&#xff0c;需要讲运算范围小的提升为运算范围大的同类&#xff0c…

软考系列必过资料分享-系统架构师-系统分析师-信息系统项目管理师

建议,写在前面 知识点是公用的,原则上不分新旧。每年会有少部分的题目切合当前时间段&#xff08;也是通过旧的知识演变的&#xff09; 信息系统项目管理师证书 系统架构师证书 系统分析师证书 资料分享 关注公众号 回复 信息系统项目管理师资料 即可获取信息系统项目管理师资…

如何使用香草看涨期权进行投机?

如何使用香草看涨期权进行投机&#xff1f; 香草看涨期权&#xff0c;通常也称为香草期权&#xff0c;是金融市场上的一种金融衍生品&#xff0c;由券商或金融机构推出。使用香草看涨期权进行投机&#xff0c;主要依赖于对市场走势的预测和对杠杆效应的运用。以下是一些关键步…

【前端】-【前端文件操作与文件上传】-【前端接受后端传输文件指南】

目录 前端文件操作与文件上传前端接受后端传输文件指南 前端文件操作与文件上传 一、前端文件上传有两种思路&#xff1a; 二进制blob传输&#xff1a;典型案例是formData传输&#xff0c;相当于用formData搭载二进制的blob传给后端base64传输&#xff1a;转为base64传输&…

力扣HOT100 - 35. 搜索插入位置

解题思路&#xff1a; 二分法模板 class Solution {public int searchInsert(int[] nums, int target) {int left 0;int right nums.length - 1;while (left < right) {int mid left ((right - left) >> 1);if (nums[mid] target)return mid;else if (nums[mid…

spring模块(六)spring监听器(1)ApplicationListener

一、介绍 1、简介 当某个事件触发的时候&#xff0c;就会执行的方法块。 当然&#xff0c;springboot很贴心地提供了一个 EventListener 注解来实现监听。 2、源码&#xff1a; package org.springframework.context;import java.util.EventListener; import java.util.fu…

深入解析智能指针:从实践到原理

&#x1f466;个人主页&#xff1a;晚风相伴 &#x1f440;如果觉得内容对你有所帮助的话&#xff0c;还请一键三连&#xff08;点赞、关注、收藏&#xff09;哦 如果内容有错或者不足的话&#xff0c;还望你能指出。 目录 智能指针的引入 内存泄漏 RAII 智能指针的使用及原…

安卓LayoutParams浅析

目录 前言一、使用 LayoutParams 设置宽高二、不设置 LayoutParams2.1 TextView 的 LayoutParams2.2 LinearLayout 的 LayoutParams 三、getLayoutParams 的使用四、setLayoutParams 的作用五、使用 setWidth/setHeight 设置宽高 前言 先来看一个简单的布局&#xff0c;先用 x…

百元挂耳式耳机哪款好?五款高品质一流机型不容错过

开放式耳机以其独特的不入耳设计&#xff0c;大大提升了佩戴的舒适度。相较于传统的入耳式耳机&#xff0c;它巧妙地避免了对耳朵的压迫&#xff0c;降低了中耳炎等潜在风险。不仅如此&#xff0c;开放式耳机还能让你保持对周边声音的灵敏度&#xff0c;无论是户外跑步还是骑行…

Day08-JavaWeb开发-MySQL(多表查询内外连接子查询事务索引)Mybatis入门

1. MySQL多表查询 1.1 概述 1.2 内连接 -- 内连接 -- A. 查询员工的姓名, 及所属的部门名称(隐式内连接实现) select tb_emp.name, tb_dept.name from tb_emp,tb_dept where tb_emp.dept_id tb_dept.id;-- 起别名 select * from tb_emp e, tb_dept d where e.dept_id d.id…

信息化飞速发展下,源代码防泄密方案该如何选择?常见四种有效方案分享

信息化时代发展迅速&#xff0c;数据防泄露一词也频繁的出现在我们身边。无论企业或政府单位&#xff0c;无纸化办公场景越来越多&#xff0c;数据泄露的时间也层出不穷。例如&#xff1a;世界最大职业中介网站Monster遭到黑客大规模攻击&#xff0c;黑客窃取在网站注册的数百万…
最新文章