Кортежи — это более легкая альтернатива объектам, когда вы хотите сгруппировать данные, поскольку для различения элементов используются позиции, а не имена свойств. Однако до сих пор кортежным типам не хватало многих полезных функций, предоставляемых объектными типами!

  1. Маркированные элементы кортежа: type T = [foo: number, bar: string]
  2. Аннотации отклонений (только для чтения/только для записи) для элементов кортежа: type T = [+foo: number, -bar: string]
  3. Необязательные элементы кортежа: type T = [foo?: number, bar?: string]
  4. Распространение кортежа type T = [number, string, ...OtherTuple]
  5. Уточнение длины кортежа

Прочтите полную документацию.

Маркированные элементы кортежа

Теперь вы можете добавить метку к элементам кортежа. Метки не влияют на тип элемента кортежа, но полезны для самостоятельного документирования назначения элементов кортежа, особенно когда несколько элементов имеют один и тот же тип.

type Range = [x: number, y: number];

Метки также необходимы для добавления к элементам аннотаций отклонений или модификаторов необязательности.

Аннотации отклонений для элементов кортежа и кортежей, доступных только для чтения.

Вы можете добавлять аннотации дисперсия (для обозначения только для чтения/только для записи) к помеченным элементам кортежа, как и к свойствам объекта:

type T = [+foo: number, -bar: string];

Это позволяет помечать элементы как доступные только для чтения или только для записи. Например:

function f(readOnlyTuple: [+foo: number, +bar: string]) {
  const n: number = readOnlyTuple[0]; // OK to read
  readOnlyTuple[1] = 1; // ERROR! Cannot write
}

Вы также можете использовать $ReadOnly для типов кортежей как сокращение для обозначения каждого свойства как доступного только для чтения:

type T = $ReadOnly<[number, string]>; // Same as `[+a: number, +b: string]`

Необязательные элементы кортежа

Вы можете пометить элементы кортежа как необязательные с помощью ? после метки элемента. Это позволяет опустить необязательные элементы. Необязательные элементы должны находиться в конце типа кортежа после всех обязательных элементов.

type T = [foo: number, bar?: string];
([1, "s"]: T); // OK: has all elements
([1]: T); // OK: skipping optional element

Вы не можете записать undefined в необязательный элемент — добавьте | void к типу элемента, если хотите:

type T = [foo?: number, bar?: number | void];
declare const x: T;
x[0] = undefined; // ERROR
([undefined]: T); // ERROR

x[1] = undefined; // OK: we've added `| void` to the element type

Вы также можете использовать типы утилит Partial и Required, чтобы сделать все элементы необязательными или обязательными соответственно:

type AllRequired = [number, string];
([]: Partial<AllRequired>); // OK: like `[a?: number, b?: string]` now

type AllOptional = [a?: number, b?: string];
([]: Required<AllOptional>); // ERROR: like `[a: number, b: string]` now

Кортежи с необязательными элементами имеют арность (длину), которая представляет собой диапазон, а не одно число. Например, [number, b?: string] имеет длину 1–2.

Распространение типа кортежа

Вы можете разделить тип кортежа на другой тип кортежа, чтобы создать более длинный тип кортежа:

type A = [number, string];
type T = [...A, boolean]; // Same as `[number, string, boolean]`
([1, "s", true]: T); // OK

Спреды кортежей сохраняют дисперсию и опциональность. Вы не можете разбивать массивы на кортежи, только на другие кортежи.

Уточнение по длине

Вы можете уточнить объединение кортежей по их длине:

type Union = [number, string] | [boolean];
function f(x: Union) {
  if (x.length === 2) {
    // `x` is `[number, string]`
    const n: number = x[0]; // OK
    const s: string = x[1]; // OK
  } else {
    // `x` is `[boolean]`
    const b: boolean = x[0];
  }
}

Технически это не новая функция, о которой ранее не сообщалось.

Принятие

Чтобы использовать помеченные элементы кортежа (включая необязательные элементы и аннотации отклонений к элементам) и элементы расширения кортежа, вам необходимо обновить свою инфраструктуру, чтобы она поддерживала синтаксис:

Бонус: declare const и declare let

Flow теперь поддерживает declare const и declare let (в дополнение к существующему declare var). Они позволяют вам объявить переменную с типом, но без реализации. Они полезны для написания определений библиотек или создания воспроизведений проблем в Try Flow при использовании современных const и let вместо устаревших var. И declare const, и declare let являются блочными, как и их эквиваленты, отличные от declare.

if (cond) {
  declare const foo: number;
}
foo; // ERROR: cannot resolve `foo` (as it's block-scoped)