Переход с существующих шаблонов
Замена 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