Я новичок в 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. Что может спасти меня от такой боли? Должен ли я просто принять определенное количество небезопасных типов устройств вокруг интерфейсов и ограждений типов?