Spec-Zone.ru › Flow

Переход с существующих шаблонов

Замена switch​

В зависимости от использования можно преобразовать switch либо в оператор match, либо в выражение match.

Если вы используете IDE, можно применить действие рефакторинга «Рефакторинг switch в match», чтобы выполнить большую часть описанных ниже действий. Для активации switch должны выполняться следующие условия:

  • Каждая ветвь switch, кроме последней, должна заканчиваться break, return или throw.
  • Если есть default, он должен быть последней ветвью.
  • Проверку case должно быть возможно преобразовать в шаблон сопоставления.
  • Если в теле ветви есть let или const, его необходимо заключить в блок.

Также следует учитывать следующие особенности итогового выражения match:

  • В нём могут остаться другие break (кроме последнего удалённого), что приведёт к ошибке разбора; вам придётся решить, как её устранить.
  • Исчерпывающая проверка может не выполняться, или шаблоны, допустимые в качестве проверок case, могут оказаться недопустимыми шаблонами сопоставления (например, если значение имеет тип только string, исчерпывающее сопоставление становится невозможным). Возникнут новые ошибки, которые вам потребуется устранить.

В оператор match​

Большинство операторов switch можно преобразовать в операторы match:

  • Замените switch на match
  • Удалите case
  • Замените двоеточие : после проверки ветви на стрелку =>
  • Заключите тело ветви в блок { ... }
  • Удалите break;
  • Если несколько ветвей используют одно тело, примените шаблон «или» |
  • Замените default на шаблон-джокер _
declare const action: 'delete' | 'remove' | 'add' | 'show';
declare const data: Array<number>;
declare function show(data: Array<number>): void;


// Before
switch (action) {
  case 'delete':
  case 'remove':
    data.pop();
    break;
  case 'add':
    data.push(1);
    break;
  default:
    show(data);
}


// After
match (action) {
  'delete' | 'remove' => {
    data.pop();
  }
  'add' => {
    data.push(1);
  }
  _ => {
    show(data);
  }
}

Если вы полагаетесь на поведение перехода к следующей ветви для ветвей switch, не используя break (за исключением простого случая, когда тело полностью совпадает), вероятно, придётся вынести код тела ветви в функцию и вызывать её.

В выражение match​

Если тело каждой ветви switch содержит только одно return или одно присваивание, можно преобразовать switch в выражение match.

Для случая return выполните те же изменения, что и в разделе «В оператор match», за исключением следующего:

  • Замените тело каждой ветви только возвращаемым выражением, удалите return и не используйте фигурные скобки для тела case
  • Разделите ветви запятой ,
  • Верните всё выражение match
// Before
function getSizeBefore(imageSize: 'small' | 'medium' | 'large') {
  switch (imageSize) {
    case 'small':
      return 50;
    case 'medium':
      return 100;
    case 'large':
      return 200;
  }
}


// After
function getSizeAfter(imageSize: 'small' | 'medium' | 'large') {
  return match (imageSize) {
    'small' => 50,
    'medium' => 100,
    'large' => 200,
  };
}

Для случая с присваиванием выполните те же изменения, что и в разделе «В оператор match», за исключением следующего:

  • Замените тело каждой ветви только присваиваемым выражением и не используйте фигурные скобки для тела case
  • Разделите ветви запятой ,
  • Присвойте переменной результат всего выражения match
  • Если переменной больше не присваивается новое значение, можно заменить её на const
declare const colorScheme: 'darker' | 'light' | 'unset';
declare const colorSchemeDarker: string;
declare const colorSchemeLight: string;
declare const colorSchemeDefault: string;


// Before
{
  let colorSchemeStyles;
  switch (colorScheme) {
    case 'darker':
      colorSchemeStyles = colorSchemeDarker;
      break;
    case 'light':
      colorSchemeStyles = colorSchemeLight;
      break;
    case 'unset':
      colorSchemeStyles = colorSchemeDefault;
      break;
  }
}


// After
{
  const colorSchemeStyles = match (colorScheme) {
    'darker' => colorSchemeDarker,
    'light' => colorSchemeLight,
    'unset' => colorSchemeDefault,
  };
}

Можно заменить несколько присваиваний одним выражением match:

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


// Before
{
  let color;
  let size;
  switch (status) {
    case Status.Active:
      color = 'green';
      size = 2;
      break;
    case Status.Paused:
      color = 'yellow';
      size = 1;
      break;
    case Status.Off:
      color = 'red';
      size = 0;
      break;
  }
}


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


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

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

Замена условных тернарных выражений​

Большинство условных выражений cond ? x : y можно заменить выражениями match. Это особенно полезно для сложных или вложенных условных выражений. Например:

declare const obj:
  | {type: 'a', foo: number}
  | {type: 'b', bar: string}
  | null;


// Before
const a =
  obj === null
    ? 0
    : obj.type === 'a'
      ? obj.foo
      : obj.bar.length;


// After
const b = match (obj) {
  {type: 'a', const foo} => foo,
  {type: 'b', const bar} => bar.length,
  null => 0,
};

Работа с непересекающимися объединениями объектов​

Непересекающиеся объединения объектов — это объединения типов объектов с некоторым отличительным свойством. В следующем примере таким свойством будет type:

type Result = {type: 'ok', value: number} | {type: 'error', error: Error};

В прежних шаблонах проверялось свойство result.type, а затем выполнялся доступ к свойствам result:

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


switch (result.type) {
  case 'ok':
    console.log(result.value);
    break;
  case 'error':
    throw result.error;
}

При сопоставлении с шаблоном нужно изменить подход. Вместо условной проверки свойства type её выполняют для самого объекта и извлекают нужные значения прямо в шаблоне:

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


match (result) {
  {type: 'ok', const value} => {
    console.log(value);
  }
  {type: 'error', const error} => {
    throw error;
  }
}

Если нужно передать сам уточнённый тип объекта, можно использовать шаблон as в шаблоне объекта:

type OK = {type: 'ok', value: number};
type Err = {type: 'error', error: Error}
type Result = OK | Err;


declare const result: Result;


match (result) {
  {type: 'ok', const value} => {
    console.log(value);
  }
  {type: 'error', ...} as err => { // Using `as`
    throw processError(err);
  }
}


declare function processError(err: Err): Error;

Если свойство type не требуется включать, можно также использовать шаблон остатка объекта:

type Result = {type: 'ok', value: number} | {type: 'error', error: Error};


declare const result: Result;


match (result) {
  {type: 'ok', const value} => {
    console.log(value);
  }
  {type: 'error', ...const err} => { // Using object rest
    throw processError(err);
  }
}


declare function processError(err: {error: Error}): Error;

См. также​

  • Уточнения типов — как сужение типов switch и if преобразуется в шаблоны сопоставления
  • Объединения — шаблоны для непересекающихся объединений часто переносят в выражения match

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

Spec-Zone.ru

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