用户定义的类型防护:我需要检查成员类型吗?

时间:2020-05-25 14:57:57

标签: typescript typeguards

我是TypeScript的新手,正在尝试了解接口和类型防护。假设我有一个描述客户端和服务器之间传递的JSON的接口:

interface Player {
  name: string
  score: number
}

我第一次为此编写类型保护的尝试是

function isPlayer (value: any): value is Player {
  const { name, score } = (value as Player)
  return typeof name == 'string' && typeof score == 'number'
}

我的IDE警告我typeof检查是多余的:'name' always has type 'string'等。相反,在《 TypeScript手册》和其他地方的以下示例中,我所需要的只是检查是否未定义成员:

function isPlayer (value: any): value is Player {
  const { name, score } = (value as Player)
  return name !== undefined && score !== undefined
}

这真的够用吗?我的第一个想法是关于保证其成员类型的类型声明value as Player。但是手册本身suggests not

类型断言是一种告诉编译器“相信我,我知道我在做什么”的方法。类型断言就像其他语言中的类型转换一样,但是不执行数据的特殊检查或重组。它对运行时没有影响,仅由编译器使用。 TypeScript假定您(程序员)已经执行了所需的任何特殊检查。

A quick experiment似乎支持这一点。我的isPlayer类型防护的宽松形式将使score是字符串的对象通过。既然是这种情况,我感到困惑,为什么我所见过的手册和每个有关类型防护的教程都只提到了未定义检查的简单形式。

说我有以下内容:

enum Stage {
  WaitingForCard = 'Waiting for card',
  PlacingBets = 'Placing bets',
  Scoring = 'Scoring',
}

interface Turn {
  stage: Stage
  players: string[]
}

看起来真正安全的类型防护必须像这样:

function isRound (v: any): v is Round {
  const { stage, players } = (v as Round)

  if (stage != Stage.WaitingForCard || stage != Stage.PlacingBets || stage != Stage.Scoring) {
    return false
  }

  return players.every(player => typeof player == 'string')
}

这似乎还不可能,因为编译器抱怨详尽的if条件。有什么可以让我免于这种痛苦的吗? 我是否只需要在接口和类型防护器周围接受一定数量的类型不安全?

1 个答案:

答案 0 :(得分:1)

TypeScript允许您对类型保护有所保留,并且不强制您检查所有(或实际上任何)属性,您可以根据需要精确或不精确(如果使用‛unknown‛这会变得有点困难)。然后是代码的问题,其中类型更改和类型防护被遗忘,导致运行时错误:(

我遇到了类似的问题,需要手动定义我的类型保护,因此我制作了一个TypeScript transformer可以自动为我做的事情。例如,在您的情况下:

import { isA } from 'ts-type-checked'; 

if (isA<Player>(value)) {
  // you are sure value is a Player here
}

您可以在NPM page的项目中找到有关如何使用它的指南。

免责声明:ofc我是图书馆的作者:)