Охранники определяемых пользователем типов: нужно ли мне проверять типы членов? - PullRequest
0 голосов
/ 25 мая 2020

Я новичок в 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', et c. Вместо этого, следуя примерам в Руководстве по TypeScript и в других местах, все, что мне нужно, это проверить, что нет элементов undefined:

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

Достаточно ли этого? Моей первой мыслью было что-то о утверждение типа value as Player, которое гарантирует типы его членов. Но само руководство предлагает не :

Утверждения типов - это способ сказать компилятору: «Поверьте мне, я знаю, что делаю». Утверждение типа похоже на приведение типа в других языках, но не выполняет специальной проверки или реструктуризации данных. Он не влияет на время выполнения и используется исключительно компилятором. TypeScript предполагает, что вы, программист, выполнили любые необходимые вам специальные проверки.

Быстрый эксперимент , похоже, подтверждает это. Расслабленная форма моего охранника типа 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 Ответ

1 голос
/ 25 мая 2020

TypeScript позволяет вам немного лениться в отношении защиты типов и не заставляет вас проверять все (или фактически любые) свойства, вы можете быть настолько точными или неточными, насколько захотите (если вы используете ‛unknown‛ становится немного сложнее). Кроме того, возникает проблема с кодом, когда типы меняются, а защита типов забывается, что приводит к ошибкам во время выполнения: (

Я столкнулся с аналогичной проблемой, мне нужно было вручную определить свои охранники типов, поэтому я сделал Преобразователь TypeScript , который может делать это за меня автоматически. Например, в вашем случае:

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

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

Вы можете найти руководство по его использованию в своем проекте на NPM page .

Отказ от ответственности: из c Я являюсь автором библиотеки:)

...