Разницы нет.Но также это совершенно разные вещи.
Я думаю, здесь есть некоторая концептуальная путаница.Вот пример необязательного параметра:
function recase(str, lower) {
if (lower) {
return str.toLowerCase();
}
return str.toUpperCase();
}
recase('Test', true)
// "test"
recase('test')
// "TEST"
recase()
// Uncaught TypeError: Cannot read property 'toUpperCase' of undefined
Наша функция принимает два аргумента.Первый обязателен, если мы не передадим хотя бы один аргумент, функция выдаст исключение.Второй является необязательным, если мы не передадим второй, то исключение не будет выдано, возвращаемое значение будет просто другим.
Обратите внимание, что я не вводил никаких типов.Это потому, что «необязательный параметр» здесь - это просто общая концепция программирования.Flow не имеет встроенной функции, называемой «необязательные параметры».Что предлагает поток, так это способ вводить необязательных параметров, называемых "возможно типами".
Итак, я хочу напечатать свою функцию выше.Ну, первый проход может выглядеть так:
// We're taking a string and a boolean and returning a string, right?
function recase(str: string, lower: boolean): string {
if (lower) {
return str.toLowerCase();
}
return str.toUpperCase();
}
recase('Test', false)
// "TEST"
recase('Test', true)
// "test"
recase('Test')
// ^ Cannot call `recase` because function [1] requires another argument.
Поскольку мы ввели lower
как boolean
, поток ожидает, что boolean
будет передан как второй аргумент.Когда мы не передаем логическое значение, поток выдает ошибку.Наш параметр больше не является обязательным.Мы можем просто удалить тип из lower
, но тогда поток по умолчанию будет lower
для any
типа, что означает, что пользователь может передавать все, что он хочет, что делает наши типы неоднозначными и подверженными ошибкам.Вот что мы могли бы сделать:
function recase(str: string, lower: void | boolean): string {
if (lower) {
return str.toLowerCase();
}
return str.toUpperCase();
}
recase('Test', true)
// "test"
recase('Test')
// "TEST"
В потоке тип void
соответствует только значению undefined
.Если мы не предоставляем значение для lower
при вызове recase
, тогда значение lower
будет undefined
, и, набрав ниже как void | boolean
, мы сказали потоку, что lower
может быть либоboolean
или undefined
(не указывается в качестве параметра).
Так что, очевидно, это очень распространенный сценарий.Настолько распространенный, что в какой-то момент мы могли бы рассмотреть возможность его инкапсуляции.Это можно сделать с помощью шаблонов, например, так:
// Let's call this Q for "Question" but it's nice and short
type Q<T> = void | null | T;
function recase(str: string, lower: Q<boolean>): string {
if (lower) {
return str.toLowerCase();
}
return str.toUpperCase();
}
Обратите внимание, что мы добавили null
к нашему универсальному типу, потому что регистр undefined
сильно совпадает с регистром null
желаниябыть в состоянии передать null
для необязательных параметров.
Ну, это настолько распространено, что поток предлагает нам то, что составляет синтаксический сахар для этой ситуации, называемый «возможно типами».Если бы вы смогли переименовать наш тип Q
в ?
, то у вас были бы, возможно, типы.
function recase(str: string, lower: ?boolean): string {
if (lower) {
return str.toLowerCase();
}
return str.toUpperCase();
}