diff --git a/packages/react-error-overlay/package.json b/packages/react-error-overlay/package.json
index 289f72126bfe05c6e652ea42be8e4ae127769b83..11ee85894478afda5c39d31409b76f4c459027e9 100644
--- a/packages/react-error-overlay/package.json
+++ b/packages/react-error-overlay/package.json
@@ -51,7 +51,7 @@
     "eslint-plugin-import": "2.7.0",
     "eslint-plugin-jsx-a11y": "5.1.1",
     "eslint-plugin-react": "7.1.0",
-    "flow-bin": "0.52.0",
+    "flow-bin": "^0.54.0",
     "jest": "20.0.4",
     "jest-fetch-mock": "1.2.1",
     "rimraf": "^2.6.1"
diff --git a/packages/react-error-overlay/src/components/Collapsible.js b/packages/react-error-overlay/src/components/Collapsible.js
index 92f1de4295c6b4ddbfa51f164aa3af31c9796ba4..0954288130a066d894d0c120b5da32b84e41f001 100644
--- a/packages/react-error-overlay/src/components/Collapsible.js
+++ b/packages/react-error-overlay/src/components/Collapsible.js
@@ -11,6 +11,8 @@
 import React, { Component } from 'react';
 import { black } from '../styles';
 
+import type { Element as ReactElement } from 'react';
+
 const _collapsibleStyle = {
   color: black,
   cursor: 'pointer',
@@ -35,7 +37,15 @@ const collapsibleExpandedStyle = {
   marginBottom: '0.6em',
 };
 
-class Collapsible extends Component {
+type Props = {|
+  children: ReactElement<any>[],
+|};
+
+type State = {|
+  collapsed: boolean,
+|};
+
+class Collapsible extends Component<Props, State> {
   state = {
     collapsed: true,
   };
diff --git a/packages/react-error-overlay/src/components/ErrorOverlay.js b/packages/react-error-overlay/src/components/ErrorOverlay.js
index 446105dad2e6decec61bc08e86b7c5a2e41a02f0..2f706f2424b421834c73524eb32afd747eb6ec99 100644
--- a/packages/react-error-overlay/src/components/ErrorOverlay.js
+++ b/packages/react-error-overlay/src/components/ErrorOverlay.js
@@ -11,6 +11,8 @@
 import React, { Component } from 'react';
 import { black } from '../styles';
 
+import type { Node as ReactNode } from 'react';
+
 const overlayStyle = {
   position: 'relative',
   display: 'inline-flex',
@@ -31,10 +33,19 @@ const overlayStyle = {
   color: black,
 };
 
-class ErrorOverlay extends Component {
+type Props = {|
+  children: ReactNode,
+  shortcutHandler?: (eventKey: string) => void,
+|};
+
+type State = {|
+  collapsed: boolean,
+|};
+
+class ErrorOverlay extends Component<Props, State> {
   iframeWindow: window = null;
 
-  getIframeWindow = (element: HTMLDivElement) => {
+  getIframeWindow = (element: ?HTMLDivElement) => {
     if (element) {
       const document = element.ownerDocument;
       this.iframeWindow = document.defaultView;
diff --git a/packages/react-error-overlay/src/containers/CompileErrorContainer.js b/packages/react-error-overlay/src/containers/CompileErrorContainer.js
index a3e89fe591d3087fc971b645a4edcc20813bdc23..9eb8c029b32d4e365deb2dd542129f77cd5f1696 100644
--- a/packages/react-error-overlay/src/containers/CompileErrorContainer.js
+++ b/packages/react-error-overlay/src/containers/CompileErrorContainer.js
@@ -15,7 +15,11 @@ import Header from '../components/Header';
 import CodeBlock from '../components/CodeBlock';
 import generateAnsiHTML from '../utils/generateAnsiHTML';
 
-class CompileErrorContainer extends PureComponent {
+type Props = {|
+  error: string,
+|};
+
+class CompileErrorContainer extends PureComponent<Props, void> {
   render() {
     const { error } = this.props;
     return (
diff --git a/packages/react-error-overlay/src/containers/RuntimeError.js b/packages/react-error-overlay/src/containers/RuntimeError.js
index c64824137d27846ad910fb26d1a694d91d5e8d2e..b21360d5e3019ef6e9d2d9193b3520e959d5cee2 100644
--- a/packages/react-error-overlay/src/containers/RuntimeError.js
+++ b/packages/react-error-overlay/src/containers/RuntimeError.js
@@ -11,6 +11,7 @@
 import React from 'react';
 import Header from '../components/Header';
 import StackTrace from './StackTrace';
+
 import type { StackFrame } from '../utils/stack-frame';
 
 const wrapperStyle = {
@@ -18,7 +19,7 @@ const wrapperStyle = {
   flexDirection: 'column',
 };
 
-type ErrorRecord = {|
+export type ErrorRecord = {|
   error: Error,
   unhandledRejection: boolean,
   contextSize: number,
diff --git a/packages/react-error-overlay/src/containers/RuntimeErrorContainer.js b/packages/react-error-overlay/src/containers/RuntimeErrorContainer.js
index 1e09724df9aaa09f2768c044f32881b7276743c5..dafd2af27addffda7042646416813c2c0b6f5b49 100644
--- a/packages/react-error-overlay/src/containers/RuntimeErrorContainer.js
+++ b/packages/react-error-overlay/src/containers/RuntimeErrorContainer.js
@@ -15,7 +15,19 @@ import NavigationBar from '../components/NavigationBar';
 import RuntimeError from './RuntimeError';
 import Footer from '../components/Footer';
 
-class RuntimeErrorContainer extends PureComponent {
+import type { ErrorRecord } from './RuntimeError';
+
+type Props = {|
+  errorRecords: ErrorRecord[],
+  close: () => void,
+  launchEditorEndpoint: ?string,
+|};
+
+type State = {|
+  currentIndex: number,
+|};
+
+class RuntimeErrorContainer extends PureComponent<Props, State> {
   state = {
     currentIndex: 0,
   };
diff --git a/packages/react-error-overlay/src/containers/StackFrame.js b/packages/react-error-overlay/src/containers/StackFrame.js
index 1dfcbb4376a41becff41be7f9b9da06525b12447..9916623564aa49095b71f8234f50750725353b58 100644
--- a/packages/react-error-overlay/src/containers/StackFrame.js
+++ b/packages/react-error-overlay/src/containers/StackFrame.js
@@ -13,6 +13,8 @@ import CodeBlock from './StackFrameCodeBlock';
 import { getPrettyURL } from '../utils/getPrettyURL';
 import { darkGray } from '../styles';
 
+import type { StackFrame as StackFrameType } from '../utils/stack-frame';
+
 const linkStyle = {
   fontSize: '0.9em',
   marginBottom: '0.9em',
@@ -43,7 +45,19 @@ const toggleStyle = {
   lineHeight: '1.5',
 };
 
-class StackFrame extends Component {
+type Props = {|
+  frame: StackFrameType,
+  launchEditorEndpoint: ?string,
+  contextSize: number,
+  critical: boolean,
+  showCode: boolean,
+|};
+
+type State = {|
+  compiled: boolean,
+|};
+
+class StackFrame extends Component<Props, State> {
   state = {
     compiled: false,
   };
@@ -54,43 +68,45 @@ class StackFrame extends Component {
     }));
   };
 
-  canOpenInEditor() {
+  getEndpointUrl(): string | null {
     if (!this.props.launchEditorEndpoint) {
-      return;
+      return null;
     }
     const { _originalFileName: sourceFileName } = this.props.frame;
     // Unknown file
     if (!sourceFileName) {
-      return false;
+      return null;
     }
     // e.g. "/path-to-my-app/webpack/bootstrap eaddeb46b67d75e4dfc1"
     const isInternalWebpackBootstrapCode =
       sourceFileName.trim().indexOf(' ') !== -1;
     if (isInternalWebpackBootstrapCode) {
-      return false;
+      return null;
     }
     // Code is in a real file
-    return true;
+    return this.props.launchEditorEndpoint || null;
   }
 
   openInEditor = () => {
-    if (!this.canOpenInEditor()) {
+    const endpointUrl = this.getEndpointUrl();
+    if (endpointUrl === null) {
       return;
     }
+
     const {
       _originalFileName: sourceFileName,
       _originalLineNumber: sourceLineNumber,
     } = this.props.frame;
     // Keep this in sync with react-error-overlay/middleware.js
     fetch(
-      `${this.props.launchEditorEndpoint}?fileName=` +
+      `${endpointUrl}?fileName=` +
         window.encodeURIComponent(sourceFileName) +
         '&lineNumber=' +
         window.encodeURIComponent(sourceLineNumber || 1)
     ).then(() => {}, () => {});
   };
 
-  onKeyDown = (e: SyntheticKeyboardEvent) => {
+  onKeyDown = (e: SyntheticKeyboardEvent<>) => {
     if (e.key === 'Enter') {
       this.openInEditor();
     }
@@ -152,7 +168,7 @@ class StackFrame extends Component {
       }
     }
 
-    const canOpenInEditor = this.canOpenInEditor();
+    const canOpenInEditor = this.getEndpointUrl() !== null;
     return (
       <div>
         <div>{functionName}</div>
diff --git a/packages/react-error-overlay/src/containers/StackFrameCodeBlock.js b/packages/react-error-overlay/src/containers/StackFrameCodeBlock.js
index 2ed685cff49dfcf98b89a9b0d66fc6e4860b0bc4..58a2c0d537cedf8619a16f133b5295cb3a7e44f5 100644
--- a/packages/react-error-overlay/src/containers/StackFrameCodeBlock.js
+++ b/packages/react-error-overlay/src/containers/StackFrameCodeBlock.js
@@ -21,12 +21,16 @@ import codeFrame from 'babel-code-frame';
 type StackFrameCodeBlockPropsType = {|
   lines: ScriptLine[],
   lineNum: number,
-  columnNum: number,
+  columnNum: ?number,
   contextSize: number,
   main: boolean,
 |};
 
-function StackFrameCodeBlock(props: StackFrameCodeBlockPropsType) {
+// Exact type workaround for spread operator.
+// See: https://github.com/facebook/flow/issues/2405
+type Exact<T> = $Shape<T>;
+
+function StackFrameCodeBlock(props: Exact<StackFrameCodeBlockPropsType>) {
   const { lines, lineNum, columnNum, contextSize, main } = props;
   const sourceCode = [];
   let whiteSpace = Infinity;
diff --git a/packages/react-error-overlay/src/containers/StackTrace.js b/packages/react-error-overlay/src/containers/StackTrace.js
index 8d81cc9429e94480f6795457c491b8b4ab2c4893..8d4a487dc7bdc9631ef7d7b840eaa8c2a2103a14 100644
--- a/packages/react-error-overlay/src/containers/StackTrace.js
+++ b/packages/react-error-overlay/src/containers/StackTrace.js
@@ -14,6 +14,8 @@ import Collapsible from '../components/Collapsible';
 import { isInternalFile } from '../utils/isInternalFile';
 import { isBultinErrorName } from '../utils/isBultinErrorName';
 
+import type { StackFrame as StackFrameType } from '../utils/stack-frame';
+
 const traceStyle = {
   fontSize: '1em',
   flex: '0 1 auto',
@@ -21,7 +23,14 @@ const traceStyle = {
   overflow: 'auto',
 };
 
-class StackTrace extends Component {
+type Props = {|
+  stackFrames: StackFrameType[],
+  errorName: string,
+  contextSize: number,
+  launchEditorEndpoint: ?string,
+|};
+
+class StackTrace extends Component<Props> {
   renderFrames() {
     const {
       stackFrames,
diff --git a/packages/react-error-overlay/src/index.js b/packages/react-error-overlay/src/index.js
index 168baa7ef6472698ad881a904637fda6bb0125f8..d44976713a6328e08d45a9725774430a6b2b1de2 100644
--- a/packages/react-error-overlay/src/index.js
+++ b/packages/react-error-overlay/src/index.js
@@ -9,6 +9,7 @@
 
 /* @flow */
 import React from 'react';
+import type { Element } from 'react';
 import ReactDOM from 'react-dom';
 import CompileErrorContainer from './containers/CompileErrorContainer';
 import RuntimeErrorContainer from './containers/RuntimeErrorContainer';
@@ -27,7 +28,7 @@ type RuntimeReportingOptions = {|
 let iframe: null | HTMLIFrameElement = null;
 let isLoadingIframe: boolean = false;
 
-let renderedElement: null | React.Element<any> = null;
+let renderedElement: null | Element<any> = null;
 let currentBuildError: null | string = null;
 let currentRuntimeErrorRecords: Array<ErrorRecord> = [];
 let currentRuntimeErrorOptions: null | RuntimeReportingOptions = null;
diff --git a/packages/react-error-overlay/src/utils/getSourceMap.js b/packages/react-error-overlay/src/utils/getSourceMap.js
index 1d8405519bd613640521d601589bed7cda1f0853..5c9e3aa9eb7ee2e93737e8ae6eec688c201bf233 100644
--- a/packages/react-error-overlay/src/utils/getSourceMap.js
+++ b/packages/react-error-overlay/src/utils/getSourceMap.js
@@ -77,7 +77,10 @@ class SourceMap {
   }
 }
 
-function extractSourceMapUrl(fileUri: string, fileContents: string) {
+function extractSourceMapUrl(
+  fileUri: string,
+  fileContents: string
+): Promise<string> {
   const regex = /\/\/[#@] ?sourceMappingURL=([^\s'"]+)\s*$/gm;
   let match = null;
   for (;;) {