Spec-Zone.ru › Flow

Выражения и инструкции match

match входное значение с рядом шаблонов, которые условно проверяют структуру входных данных и извлекают значения, а затем либо возвращают выражение (match выражения), либо выполняют блок (match инструкции).

Вы можете заменить инструкции switch с помощью match, избежав проблем, связанных с switch (например, перехода к следующей ветви), и получив такие преимущества, как проверка полноты и поддержка сложных шаблонов.

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

import * as React from 'react';


component AgePane(
  maybeAge?: {type: 'valid', age: number} | {type: 'error', msg: string}
) {
  return match (maybeAge) {
    {type: 'valid', const age} if (age < 0) =>
      <Err>Age cannot be negative!</Err>,
    {type: 'valid', const age} => <Pane>Age: {age}</Pane>,
    {type: 'error', const msg} => <Err>{msg}</Err>,
    undefined => <Err>Age is not defined.</Err>,
  };
}


component Err(children: React.Node) { return <div>{children}</div>; }
component Pane(children: React.Node) { return <div>{children}</div>; }
Сравнение с TypeScript

match доступно только в Flow — в TypeScript нет встроенной конструкции сопоставления с образцом. Полное сравнение см. в разделе «Выражения и инструкции match».

Выражения match​

Выражения match позволяют задавать условную логику в виде выражения. Они могут заменить вложенные условные тернарные выражения.

Выражение match состоит из аргумента и ряда вариантов, каждый из которых задаёт шаблон и тело выражения. Шаблоны проверяются по очереди, а результатом становится выражение, соответствующее совпавшему шаблону. Тип результата — объединение типов всех выражений вариантов.

После шаблона можно указать условие с помощью синтаксиса if (<cond-expression>). Если шаблон совпадает, также вычисляется выражение условия, и весь вариант считается совпавшим только в том случае, если результат является истинным.

Пример структуры:

const e = match (<arg>) {
  <pattern-1> => <expression-1>,
  <pattern-2> if (<cond>) => <expression-2>,
  <pattern-3> => <expression-3>,
};

Условие применяется ко всему шаблону, включая шаблоны «или». Например, 1 | 2 if (cond) сначала даст совпадение, если значение равно 1 | 2, а окончательно совпадёт, только если cond также истинно. Варианты с условием не учитываются при проверке полноты, поскольку совпадение может зависеть от условия.

Вы можете инициализировать две или более переменных с помощью match — например, кортежем:

enum Status {Active, Paused, Off}
declare const status: Status;


const [color, size] = match (status) {
  Status.Active => ['green', 2],
  Status.Paused => ['yellow', 1],
  Status.Off => ['red', 0],
};

или объектом (особенно удобно для более чем двух переменных):

enum Status {Active, Paused, Off}
declare const status: Status;


const {color, size} = match (status) {
  Status.Active => {color: 'green', size: 2},
  Status.Paused => {color: 'yellow', size: 1},
  Status.Off => {color: 'red', size: 0},
};

Выражения match нельзя использовать в позиции оператора-выражения, поскольку она предназначена для инструкций match.

match (<arg>) {} //  This is a match statement, not a match expression

Если ни один шаблон не совпадёт, Flow выдаст ошибку из-за неполного сопоставления, а во время выполнения будет выброшено исключение. В качестве последнего варианта match можно использовать шаблон-универсал (_) или шаблон объявления переменной (const x), чтобы обработать все оставшиеся возможные совпадения.

Чтобы выбросить исключение в теле варианта выражения match, нельзя использовать throw, поскольку это инструкция, а выражения match требуют тела-выражения. Вместо этого можно использовать invariant(false, <msg>), которое Flow понимает как выражение, всегда выбрасывающее исключение с указанным сообщением.

Тела вариантов выражений match пока не поддерживают использование yield, yield* или await. В отличие от выражений match, инструкции match поддерживают эти ключевые слова.

Примечание: Открывающая фигурная скобка { должна находиться в той же строке, что и аргумент match match (<arg>). Благодаря этому мы можем добавить эту возможность, сохранив обратную совместимость со всем существующим синтаксисом: match(x); по-прежнему является вызовом функции с именем match. Prettier автоматически форматирует выражения match таким образом.

Инструкции match​

Инструкции match могут заменить инструкции switch или цепочки инструкций if-else. Как и выражения match, они содержат аргумент и ряд вариантов. Разница в том, что тело каждого варианта представляет собой блок (то есть { ...statements... }), а не выражение; кроме того, эта конструкция является инструкцией и поэтому не возвращает значение. break не требуется: выполнение не переходит к следующему варианту (но вы по-прежнему можете объединять несколько шаблонов, используя шаблоны «или» |).

Пример структуры:

match (<arg>) {
  <pattern-1> => {
    <statements-1>;
  }
  <pattern-2> if (<cond>) => {
    <statements-2>;
  }
  <pattern-3> => {
    <statements-3>;
  }
}

Примечание: Как и в выражениях match, открывающая фигурная скобка { должна находиться в той же строке, что и аргумент match match (<arg>).

Проверка полноты​

match требует учесть все возможные варианты входных данных. Если этого не сделать, Flow выдаст ошибку [match-not-exhaustive] и укажет конкретные шаблоны, которые нужно добавить, чтобы сопоставление было полным. Это особенно полезно, когда тип входных данных меняется: добавление нового варианта в объединение выявляет все места сопоставления, где он не обработан. Так незаметный переход к следующей ветви во время выполнения превращается в локальную ошибку типа.

declare const tab: 'home' | 'details' | 'settings';


match (tab) { // ERROR [match-not-exhaustive]
  'home' => {}
  'settings' => {}
}

Поддерживается проверка непересекающихся объединений объектов.

declare const result: {type: 'ok', value: number} | {type: 'error'};


match (result) { // ERROR
  {type: 'error'} => {}
}

Это работает даже для вложенных структур:

function getStyle(
  align: 'start' | 'end',
  position: 'above' | 'below',
) {
  return match ([align, position]) { // ERROR
    ['start', 'above'] => 0,
    ['start', 'below'] => 1,
    ['end', 'above'] => 2,
  };
}

Flow также выдаст ошибку, если шаблон не используется:

declare const tab: 'home' | 'details' | 'settings';


match (tab) {
  'home' => {}
  'details' => {}
  'settings' => {}
  'invalid' => {} // ERROR
}

Дополнительно​

Подробнее о шаблонах match, включая шаблоны примитивных значений, массивов и объектов, шаблоны объявления переменных, а также шаблоны «или» и «как».

Вы также можете перейти с существующих конструкций, например switch или условных тернарных выражений.

Подключение​

  • Flow: включено по умолчанию начиная с Flow v0.317. В более ранних версиях добавьте pattern_matching=true в .flowconfig, в разделе [options].
    • Шаблоны экземпляров проверяются по типам по умолчанию начиная с Flow v0.317.
  • Babel: используйте flow-parser/babel-plugin; подробности см. в нашем руководстве по Babel.
  • ESLint: используйте flow-eslint; подробности см. в нашем руководстве по ESLint.

См. также​

  • Объединения — часто сопоставляются с непересекающимися объединениями
  • Перечисления Flow — перечисления хорошо сочетаются с выражениями match при проверке полноты

© 2013–present Facebook Inc.
Licensed under the MIT License.
https://flow.org/en/docs/match

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API