Flow - это средство проверки типов, созданное Facebook для проверки типов данных JavaScript. Он имеет множество встроенных типов данных, которые мы можем использовать для аннотирования типов переменных и параметров функций.
В этой статье мы рассмотрим некоторые типы встроенных утилит, которые поставляются с Flow.
$ Ключи ‹T›
Тип $Keys<T>
получает свойства от типа и использует его как свой собственный тип. Это также полезно для создания перечислений.
Например, мы можем написать:
const fruits = { apple: 'Apple', orange: 'Orange', banana: 'Banana' }; type Fruit = $Keys<typeof fruits>; let a: Fruit = 'apple';
Приведенный выше код определит новый тип Fruit
с объединением ключей объекта fruits
. Это означает, что с переменной типа Fruit
мы можем присвоить ей 'apple'
, 'orange'
или 'banana'
.
Назначение чего-либо еще должно вызвать ошибку:
let b: Fruit = 'grape';
$ Values ‹T›
Тип $Values<T>
позволяет нам получать типы типа объекта и создавать тип из их объединения.
Например, мы можем написать:
type Person = { name: string, age: number, }; type PersonValues = $Values<Person>; let a: PersonValues = 1; let b: PersonValues = 'Joe';
В коде мы определили тип Person
с некоторыми свойствами, а затем $Values<Person>
берет типы name
и age
и создает из них объединение. Итак, тип PeronValues
string | number
.
$ ReadOnly ‹T›
$ReadOnly<T>
дает нам доступную только для чтения версию типа T
.
Следующий:
type ReadOnlyObj = { +foo: string };
а также:
type ReadOnlyObj = $ReadOnly<
{
foo: string
}>;
эквивалентны.
Это удобно, когда мы хотим переопределить все свойства типа объекта как доступные только для чтения.
Например, мы можем написать следующее, чтобы определить тип и объект только для чтения:
type Person = { name: string, age: number, }; type ReadOnlyPerson = $ReadOnly<Person>; let person: ReadOnlyPerson = { name: 'Joe', age: 10 }
Затем, когда мы пытаемся переназначить свойство в объекте person
следующим образом:
person.name = 'Bob';
Мы получим ошибку.
$ Exact ‹T›
$Exact<T>
позвольте нам создать точный тип из типа объекта.
Это означает, что:
type ExactPerson = $Exact<{name: string}>;
такой же как:
type ExactPerson = {| name: string |};
$ Diff ‹A, B›
$Diff<A, B>
создает тип со свойствами, которые есть в A
, но не в B
, где оба являются типами объектов. Это то же самое, что и A \ B
, что представляет собой установленную разницу между A
и B
.
Например, если у нас есть 2 типа:
type Person = { name: string, age: number, }; type Age = { age: number };
Затем мы можем создать тип объекта, который принимает свойство name
, с помощью:
type Name = $Diff<Person, Age>;
Когда мы создаем объект с типом Name
, нам требуется свойство name
:
let name: Name = { name: 'Mary' };
Если свойство name
не включено в объект:
let foo: Name = { age: 10 };
Тогда мы получим ошибку.
$ Остальное ‹A, B›
$Rest<A, B>
похож на $Diff<A, B>
, но проверка свойств выполняется во время выполнения. Это свойства, которые являются частью оператора rest.
В результате получаются свойства собственных свойств A
, которые не являются собственными свойствами B
. В Flow определенные типы объектов рассматриваются как имеющие собственные свойства.
Например, мы можем определить новый тип объекта с $Rest<A, B>
, запустив:
type Person = { name: string, age: number };
const person: Person = {name: 'Jon', age: 42};
const {age, ...rest} = person;
(name: $Rest<Person, {|age: number|}>);
Тогда объект name
не может больше иметь свойство age
, поскольку мы привели его к типу $Rest<Person, {|age: number|}>
. $Rest<Person, {|age: number|}>
возвращает новый тип со свойством age
, удаленным из типа Person
.
$ PropertyType ‹T, k›
$PropertyType<T, k>
получает тип ключа k
от типа T
. Ключ k
- это строка. Например, если мы создадим тип Person
следующим образом:
type Person = { name: string, age: number };
Тогда $PropertyType<Person, ‘name’>
даст нам string
тип:
let foo: $PropertyType<Person, 'name'> = 'name';
Вложенные поиски тоже работают. Например, мы можем написать:
type Person = { name: { firstName: string, lastName: string }, age: number }; let foo: <$PropertyType<$PropertyType<Person, 'name'>, 'firstName'> = 'name';
$ ElementType ‹T, K›
$ElementType<T, K>
- это тип, который представляет каждый элемент в массиве, кортеже или типе объекта T
, который соответствует имени ключа K
.
Например, если у нас есть следующий тип:
type Person = { name: string, age: number };
Затем мы можем использовать его для получения типа свойства name
, написав:
$ElementType<Person, 'name'>
А затем мы можем использовать его для аннотирования типа других переменных:
let foo: $ElementType<Person, 'name'> = 'name';
Мы можем использовать его с кортежами следующим образом:
type Tuple = [boolean, string]; let foo: $ElementType<Tuple, 0> = true;
С динамическими типами объектов мы можем передать тип ключа непосредственно второму аргументу. Например, если у нас есть следующий тип:
type DynamicObj = { [key: string]: number };
Затем мы можем получить тип ключей свойств с $ElementType
, написав:
let x: $ElementType<DynamicObj, string> = 1;
Для массивов мы можем написать следующее:
type StrArrayObj = { strings: Array<string>, }; let x: $ElementType<$ElementType<StrArrayObj, 'strings'>, number> = 'abc';
Приведенный выше код работает следующим образом. $ElementType<StrArrayObj, ‘strings’>
дает нам тип свойства strings
для StrArrayObj
. Затем мы применяем $ElementType
с $ElementType<StrArrayObj, ‘strings’>
и number
, чтобы получить тип элементов массива strings
.
number
предназначен для получения индекса массива strings
.
В Flow есть много полезных типов утилит, которые упрощают создание новых типов. Мы можем получить ключи объекта для создания нового типа объединения. Также мы можем получить типы значений и создать из них новый тип объединения.
Также есть тип, позволяющий изменить все свойства на доступ только для чтения. Мы также можем получить типы ключей объекта, кортежи или записи массивов.