Как использовать защиту типов в TypeScript
typeof
, instanceof
и оператор in
, которые используются для определения того, содержит ли объект свойство.Защита типа — техника TypeScript, используемая для получения информации о типе переменной, обычно в условном блоке. Защитники типов — обычные функции, возвращающие логическое значение, принимающие тип и сообщающие TypeScript, можно ли его сузить до чего-то более конкретного. Защитники типов обладают уникальным свойством гарантировать, что проверяемое значение имеет заданный тип в зависимости от возвращаемого логического значения.
TypeScript использует некоторые встроенные операторы JavaScript, такие, как typeof
, instanceof
и оператор in
, которые используются для определения того, содержит ли объект свойство. Защитники типов позволяют указать компилятору TypeScript вывести определённый тип переменной в определённом контексте, гарантируя, что тип аргумента соответствует тому, что вы говорите.
Защитники типов обычно используются для сужения типа и очень похожи на обнаружение свойств, позволяя вам определить правильные методы, прототипы и свойства значения. Таким образом, вы можете легко понять, как работать с этим значением.
Существует пять основных способов использования защиты типа:
- Ключевое слово
instanceof
- Ключевое слово
typeof
- Ключевое слово
in
- Защита типа сужения равенства
- Пользовательская защита типа с предикатом
В этой статье мы рассмотрим четыре перечисленных выше метода. Давайте приступим!
Защита типа instanceof
instanceof
— это встроенная защита типа, которую можно использовать для проверки того, является ли значение экземпляром заданной функции-конструктора или класса. С помощью этой защиты типа мы можем проверить, является ли объект или значение производным от класса, что полезно для определения типа экземпляра типа.
Ниже приведён основной синтаксис для защиты типа instanceof
:
objectVariable instanceof ClassName;
В приведённом ниже примере мы видим пример защиты типа instanceof
:
interface Accessory {
brand: string;
}
class Necklace implements Accessory{
kind: string;
brand: string;
constructor(brand: string, kind: string) {
this.brand = brand;
this.kind = kind;
}
}
class bracelet implements Accessory{
brand: string;
year: number;
constructor(brand: string, year: number) {
this.brand = brand;
this.year = year;
}
}
const getRandomAccessory = () =>{
return Math.random() < 0.5 ?
new bracelet('cartier', 2021) :
new Necklace('choker', 'TASAKI');
}
let Accessory = getRandomAccessory();
if (Accessory instanceof bracelet) {
console.log(Accessory.year);
}
if (Accessory instanceof Necklace) {
console.log(Accessory.brand);
}
Приведённая выше функция getRandomAccessory
возвращает объект Necklace
или bracelet
, поскольку они оба реализуют интерфейс Accessory
. Подписи конструкторов для Necklace
и bracelet
различны, и защита типа instanceof
сравнивает обе подписи конструкторов для эффективного определения типа.
Защита типа typeof
Ограничитель типа typeof
используется для определения типа переменной. Считается, что защита типа typeof
является очень ограниченной и неглубокой. Он может определять только следующие типы, распознаваемые JavaScript:
boolean
string
bigint
symbol
undefined
function
number
Для всего, что не входит в этот список, защитник типа typeof
просто возвращает объект.
Защитник типа typeof
может быть записан следующими двумя способами:
typeof v !== "typename"
#or
typeof v === "typename"
typename
может быть string
, number
, symbol
или boolean
.
В приведённом ниже примере переменная StudentId
имеет тип объединения параметров string | number
. Мы видим, что если переменная является string
, то выводится Student
, а если это число, то выводится Id
. Защитный элемент typeof
помогает нам извлечь тип из x
:
function StudentId(x: string | number) {
if (typeof x == 'string') {
console.log('Student');
}
if (typeof x === 'number') {
console.log('Id');
}
}
StudentId(`446`); //выводит Student
StudentId(446); //выводит Id
Защита типа in
Защита типа in
проверяет, обладает ли объект определённым свойством, используя его для различения разных типов. Обычно он возвращает логическое значение, которое указывает, существует ли свойство у данного объекта. Он используется для сужения возможностей, а также для проверки поддержки браузером.
Ниже приведён основной синтаксис для защиты типа in
:
propertyName in objectName
В приведённом ниже примере защитник типа in
проверяет, существует ли свойство house
. В тех случаях, когда он существует, возвращается логическое значение true
, а когда не существует, возвращается false
.
"house" in { name: "test", house: { parts: "door" } }; // => true
"house" in { name: "test", house: { parts: "windows" } }; // => true
"house" in { name: "test", house: { parts: "roof" } }; // => true
"house" in { name: "test" }; // => false
"house" in { name: "test", house: undefined }; // => true
Другой подобный пример работы защиты типа in
показан ниже:
interface Pupil {
ID: string;
}
interface Adult {
SSN: number;
}
interface Person {
name: string;
age: number;
}
let person: Pupil | Adult | Person = {
name: 'Britney',
age: 6
};
const getIdentifier = (person: Pupil | Adult | Person) => {
if ('name' in person) {
return person.name;
}
else if ('ID' in person) {
return person.ID
}
return person.SSN;
}
Защита типа сужения равенства
Сужение равенства проверяет значение выражения. Для того чтобы две переменные были равны, обе переменные должны иметь одинаковый тип. Если тип переменной неизвестен, но она равна другой переменной с точным типом, то TypeScript сузит тип первой переменной с помощью информации, которую предоставляет известная переменная:
function getValues(a: number | string, b: string) {
if (a === b) {
// здесь происходит сужение, сужение до string
console.log(typeof a) // string
} else {
// если сужение не происходит, тип остаётся неизвестным
console.log(typeof a) // number или string
}
}
Если переменная a
равна переменной b
, то обе они должны иметь одинаковый тип. В данном случае TypeScript сужает его до string
. Без сужения тип a
остаётся неясным, потому что это может быть либо number
, либо string
.
Пользовательская защита типа с предикатом
Создание пользовательской защиты типов — это, как правило, самый мощный вариант использования защит типов. Когда вы создаёте пользовательскую защиту типов, написав её самостоятельно, нет никаких ограничений на то, что вы можете проверить. Однако если пользовательская защита типов написана неправильно, это может привести к множеству ошибок. Поэтому точность является ключевым фактором.
Пример пользовательской защиты типов показан ниже:
interface Necklace{
kind: string;
brand: string;
}
interface bracelet{
brand: string;
year: number;
}
type Accessory = Necklace | bracelet;
const isNecklace = (b: Accessory): b is Necklace => {
return (b as Necklace).kind !== undefined
}
const Necklace: Accessory = {kind: "Choker", brand: "TASAKI"};
const bracelet: Accessory = {brand: "Cartier", year: 2021};
console.log(isNecklace(bracelet)) //Выводит false
console.log(isNecklace(Necklace)) //Выводит true
В приведённом выше коде предикат типа b is Necklace
заставит TypeScript уменьшить тип до Necklace
вместо того, чтобы вернуть просто логическое значение.
Заключение
Защита типов в TypeScript помогает гарантировать значение типа, улучшая общий поток кода. В этой статье мы рассмотрели несколько наиболее полезных защит типов в TypeScript, изучили несколько примеров, чтобы увидеть их в действии.
В большинстве случаев для решения вашей задачи можно использовать либо защиту типа instanceof
, либо защиту типа typeof
, либо защиту типа in
, однако в случае крайней необходимости вы можете использовать пользовательскую защиту типа.
Надеюсь, вам понравилась эта статья!