概述
- 关于断言,就是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”不能作为索引类型使用