类型断言

92 阅读2分钟

类型断言

  1. A兼容B或B兼容A,可使A被断言为B
  2. 联合类型可被断言为其中一个类型
  3. 父类可断言为子类,子类也可断言为父类
  4. any可断言为任意类型, 任意类型可断言为any

语法:as newType或<>,将变量的已有类型断言为新类型,在typescript类型分析不符合预期,将其断言为正确类型

  interface user {
    name: string
  }
  let User = {} as user
  let User: Partial<user>

将父类断言为具体的子类

class b extends a {
    id: number = 0
}
class c extends a {
    name: string = 'x'
}
const isB = (param: a) => {
    if ((param as b).id) {
        return true
    }
    return false
}

当原类型和断言类型差异过大,例如将string断言为number,会类型报错,这时应先断言到unknown或any类型,再断言到预期类型

  // 双重断言
  const str: string = 'name'
  let num = str as unknown as number
  num = 1 // console.log(num) 1
  
  // 非空断言 !
  declare const userInfo: {
    prop?: () => ({
        name?: string
    })
  }
  userInfo.prop!().name!

const断言

用const代替类型名称断言构造新的文字表达式,表示:

  1. 该表达式中的字面类型不应被扩展(不能从'xx'转换为string)
  2. 对象字面量获取只读属性
  3. 数组文字成为只读元组
let a = 'x'  // let a: string
const b = 'x' // const b: 'x'
let c = 'x' as const // let c: 'x'
interface user {
  name: string,
  age: number
}
const info = (n: number) => {
  return {
    name: 'x',
    age: n
  } as const
}
const a = info(1) // info(n: number): { readonly name: "x"; readonly age: number; }
const arr = [1,2,3]
arr.push(4) // [1, 2, 3, 4] 

const arr1 = [1,2,3] as const
arr1.push(4) // Property 'push' does not exist on type 'readonly [1, 2, 3]'

显示赋值断言/非空断言操作符

在实例属性和变量声明之后加一个!,表示这个变量确实已被赋值

function initialize() {
  x = 10
}
let x: number
initialize()
console.log(x + x) //-   Variable 'x' is used before being assigned.
function initialize() {
  x = 10
}
// notice the !
let x!: number
initialize()
console.log(x + x) // no error

在上下文中当类型检查器无法断定类型,“!”可以用于断言操作对象是非null和非undefined类型的。

type entity = {
  name: string
}
function validate(e?: entity) {
  let a = e.name // e是null或无效实体,就会抛出异常 'e' is possibly 'undefined'
}

function process(e?: entity) {
  let a = e!.name
}

断言签名

  • 断言函数:在非预期结果时抛出一个错误
  • 一种断言签名模拟了断言函数的功能,确保在断言范围内,无论什么判断条件都必须为真
function assert(condition: any, msg?: string): asserts condition {
  if (!condition) {
    throw new Error(msg)
  }
}
// 如果assert函数成功返回,则传入的condition必须为真,否则就会抛出一个Error
  • 另一种断言签名不通过检查条件语句实现,而是在typeScript显示指定某个变量或属性具有不同类型
function assertsIsString(val: any): asserts val is string {
  if (typeof val !== "string") {
    throw new Error("not a string")
  }
}
// "asserts val is string" 保证函数调用后,传入的任何变量都可以被视为是string类型

导入断言

import obj from "obj.json" assert { type: "json" }
// typescript允许, 但浏览器可能报错

动态的import()调用可以通过assert属性使用导入断言(assert类型为ImportCallOptions)

const obj = await import("obj.json",{
  assert: { type: "json" }
})