Я читал PR контекстного API для React Эндрю Кларка и увидел следующий код:
((frame: any): FrameDev).debugElementStack = [];
Синтаксис был мне незнаком, когда я впервые прочитал его, к счастью, там был комментарий, объясняющий, как это работает, но я подумал, что это требует более подробного объяснения.
Поскольку Flow основан на JavaScript, типы, которые вы можете создавать с его помощью, более гибкие, чем типы, которые вы создаете в языках, в которых типы встроены в спецификацию.
В документах Flow кратко упоминаются небезопасные приведения типов:
Приведя значение к любому, вы можете затем привести его к чему угодно.
Это небезопасно и не рекомендуется. Но иногда это полезно, когда вы делаете что-то со значением, которое очень сложно или невозможно ввести, и хотите убедиться, что результат имеет желаемый тип.
Причина, по которой этот метод не описан более подробно, заключается в том, что это взлом. Однако этот хак уникален для систем типов, таких как Flow, и позволяет сбалансировать свободу свободных типов с безопасностью статических типов, поэтому стоит разобраться в этом подробнее.
Рассмотрим следующий код:
// @flow const toString = (num: number) => { return num.toString(); }; const add = (a: number, b: number) => { return a + b; }; const a = toString(1); const b = toString(2); add(a, b);
Это даст вам следующую ошибку в Flow:
string This type is incompatible with the expected param type of number
В языке со статической типизацией нам пришлось бы каждый раз проверять тип переменной, а затем преобразовывать ее. Это пример того, как небезопасное приведение типов позволяет нам обменять часть безопасности статического типа на свободу свободного типа:
const a = (toString(1): any); const b = (toString(2): any); add(a, b);
Это сбрасывает тип a
и b
на any
, который в этом случае может перейти в number
. К сожалению, этот сброс также приводит к ошибке следующего кода:
const a = (toString(1): any); const b = ("string": any); add(a, b);
Потому что "string" + 1
— это допустимый JavaScript, который оценивает to"string1"
из-за приведения типов, что является основной причиной существования Flow, поэтому это хак. Чтобы теперь Flow выдал ошибку, вам нужно сделать что-то конкретное для этой переменной:
const add = (a: number, b: number) => { a = a.toFixed(a); // format a to two decimals return a + b; }; const a = (toString(1): any); const b = ("string": any); add(a, b);
В этом случае Flow выдаст ошибку a = a.toFixed(a)
с:
string This type is incompatible with the expected param type of number
Вам следует избегать этой техники, когда это возможно, но, поняв, как она работает, вы сможете применять ее выборочно и сэкономить много времени.