[Typescript] Type Guard: is & assert

value is Foo

The first kind of user-defined type guard we will review is an is type guard. It is perfectly suited for our example above because it’s meant to work in cooperation with a control flow statement of some sort, to indicate that different branches of the “flow” will be taken based on an evaluation of valuetoTest’s type. Pay very close attention to isCarLike’s return type

interface CarLike {
  make: string
  model: string
  year: number
}
 
let maybeCar: unkNown
 
// the guard
function isCarLike(
  valuetoTest: any // should be flexable
): valuetoTest is CarLike {
  return (
    valuetoTest &&
    typeof valuetoTest === "object" &&
    "make" in valuetoTest &&
    typeof valuetoTest["make"] === "string" &&
    "model" in valuetoTest &&
    typeof valuetoTest["model"] === "string" &&
    "year" in valuetoTest &&
    typeof valuetoTest["year"] === "number"
  )
}
 
// using the guard
if (isCarLike(maybeCar)) {
  maybeCar // CarLike
}

 

asserts value is Foo

There is another approach we Could take that eliminates the need for a conditional. Pay very close attention to assertsIsCarLike’s return type:

interface CarLike {
  make: string
  model: string
  year: number
}
 
let maybeCar: unkNown
 
// the guard
function assertsIsCarLike(
  valuetoTest: any
): asserts valuetoTest is CarLike {
  if (
    !(
      valuetoTest &&
      typeof valuetoTest === "object" &&
      "make" in valuetoTest &&
      typeof valuetoTest["make"] === "string" &&
      "model" in valuetoTest &&
      typeof valuetoTest["model"] === "string" &&
      "year" in valuetoTest &&
      typeof valuetoTest["year"] === "number"
    )
  )
    throw new Error(
      `Value does not appear to be a CarLike${valuetoTest}`
    )
}

maybeCar // unkNown
assertsIsCarLike(maybeCar)
maybeCar // CarLike

 

Conceptually, what’s going on behind the scenes is very similar. By using this special Syntax to describe the return type, we are informing TypeScript that if assertsIsCarLike throws an error, it should be taken as an indication that the valuetoTest is NOT type-equivalent to CarLike.

Therefore, if we get past the assertion and keep executing code on the next line, the type changes from unkNown to CarLike.

 

Writing high-quality guards

Type guards can be thought of as part of the “glue” that connects compile-time type-checking with the execution of your program at runtime. It’s of great importance that these are designed well, as TypeScript will take you at your word when you make a claim about what the return value (or throw/no-throw behavior) indicates.

Let’s look at a bad example of a type guard:

function isNull(val: any): val is null {
  return !val
}
 
const empty = ""
const zero = 0
if (isNull(zero)) {
  console.log(zero) // is it really impossible to get here?
}
function isNull(val: any): val is null {
  return !val
}
 
const empty = ""
const zero = 0
if (isNull(zero)) {
  console.log(zero) // is it really impossible to get here?
               
const zero: never
}
if (isNull(empty)) {
  console.log(empty) // is it really impossible to get here?
}

 

相关文章

我最大的一个关于TypeScript的问题是,它将原型的所有方法(无...
我对React很新,我正在尝试理解子组件之间相互通信的简洁方法...
我有一个非常简单的表单,我将用户电子邮件存储在组件的状态,...
我发现接口非常有用,但由于内存问题我需要开始优化我的应用程...
我得到了一个json响应并将其存储在mongodb中,但是我不需要的...
我试图使用loadsh从以下数组中获取唯一类别,[{"listing...