Convert files to typescript

The change converts the following files to typescript:

* elements/diff/gr-diff-processor/gr-diff-processor.ts

Change-Id: I4aa8427d25547d2211e0dfb40cf13a53c47f4b6b
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor.ts b/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor.ts
index aa8f0a3..74164a8 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor.ts
@@ -14,24 +14,44 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin.js';
-import {PolymerElement} from '@polymer/polymer/polymer-element.js';
-import {GrDiffLine, GrDiffLineType, FILE} from '../gr-diff/gr-diff-line.js';
-import {GrDiffGroup, GrDiffGroupType, hideInContextControl} from '../gr-diff/gr-diff-group.js';
-import {util} from '../../../scripts/util.js';
+import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
+import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
+import {PolymerElement} from '@polymer/polymer/polymer-element';
+import {
+  GrDiffLine,
+  GrDiffLineType,
+  FILE,
+  Highlights,
+} from '../gr-diff/gr-diff-line';
+import {
+  GrDiffGroup,
+  GrDiffGroupType,
+  hideInContextControl,
+} from '../gr-diff/gr-diff-group';
+import {CancelablePromise, util} from '../../../scripts/util';
+import {customElement, property} from '@polymer/decorators';
+import {DiffContent} from '../../../types/common';
+import {DiffSide} from '../gr-diff/gr-diff-utils';
 
 const WHOLE_FILE = -1;
 
-const DiffSide = {
-  LEFT: 'left',
-  RIGHT: 'right',
-};
+interface State {
+  lineNums: {
+    left: number;
+    right: number;
+  };
+  chunkIndex: number;
+}
 
-const DiffHighlights = {
-  ADDED: 'edit_b',
-  REMOVED: 'edit_a',
-};
+interface ChunkEnd {
+  offset: number;
+  keyLocation: boolean;
+}
+
+interface KeyLocations {
+  left: {[key: string]: boolean};
+  right: {[key: string]: boolean};
+}
 
 /**
  * The maximum size for an addition or removal chunk before it is broken down
@@ -67,63 +87,31 @@
  *    "expand context" widget. This may require splitting a chunk/group so
  *    that the part that is within the context or has comments is shown, while
  *    the rest is not.
- *
- * @extends PolymerElement
  */
-class GrDiffProcessor extends GestureEventListeners(
-    LegacyElementMixin(
-        PolymerElement)) {
-  static get is() { return 'gr-diff-processor'; }
+@customElement('gr-diff-processor')
+export class GrDiffProcessor extends GestureEventListeners(
+  LegacyElementMixin(PolymerElement)
+) {
+  @property({type: Number})
+  context = 3;
 
-  static get properties() {
-    return {
+  @property({type: Array, notify: true})
+  groups: GrDiffGroup[] = [];
 
-      /**
-       * The amount of context around collapsed groups.
-       */
-      context: Number,
+  @property({type: Object})
+  keyLocations: KeyLocations = {left: {}, right: {}};
 
-      /**
-       * The array of groups output by the processor.
-       */
-      groups: {
-        type: Array,
-        notify: true,
-      },
+  @property({type: Number})
+  _asyncThreshold = 64;
 
-      /**
-       * Locations that should not be collapsed, including the locations of
-       * comments.
-       */
-      keyLocations: {
-        type: Object,
-        value() { return {left: {}, right: {}}; },
-      },
+  @property({type: Number})
+  _nextStepHandle: number | null = null;
 
-      /**
-       * The maximum number of lines to process synchronously.
-       */
-      _asyncThreshold: {
-        type: Number,
-        value: 64,
-      },
+  @property({type: Object})
+  _processPromise: CancelablePromise<void> | null = null;
 
-      /** @type {?number} */
-      _nextStepHandle: Number,
-      /**
-       * The promise last returned from `process()` while the asynchronous
-       * processing is running - `null` otherwise. Provides a `cancel()`
-       * method that rejects it with `{isCancelled: true}`.
-       *
-       * @type {?Object}
-       */
-      _processPromise: {
-        type: Object,
-        value: null,
-      },
-      _isScrolling: Boolean,
-    };
-  }
+  @property({type: Boolean})
+  _isScrolling?: boolean;
 
   /** @override */
   attached() {
@@ -140,22 +128,23 @@
 
   _handleWindowScroll() {
     this._isScrolling = true;
-    this.debounce('resetIsScrolling', () => {
-      this._isScrolling = false;
-    }, 50);
+    this.debounce(
+      'resetIsScrolling',
+      () => {
+        this._isScrolling = false;
+      },
+      50
+    );
   }
 
   /**
    * Asynchronously process the diff chunks into groups. As it processes, it
    * will splice groups into the `groups` property of the component.
    *
-   * @param {!Array<!Gerrit.DiffChunk>} chunks
-   * @param {boolean} isBinary
-   *
-   * @return {!Promise<!Array<!Object>>} A promise that resolves with an
-   *     array of GrDiffGroups when the diff is completely processed.
+   * @return A promise that resolves with an
+   * array of GrDiffGroups when the diff is completely processed.
    */
-  process(chunks, isBinary) {
+  process(chunks: DiffContent[], isBinary: boolean) {
     // Cancel any still running process() calls, because they append to the
     // same groups field.
     this.cancel();
@@ -165,61 +154,65 @@
 
     // If it's a binary diff, we won't be rendering hunks of text differences
     // so finish processing.
-    if (isBinary) { return Promise.resolve(); }
+    if (isBinary) {
+      return Promise.resolve();
+    }
 
     this._processPromise = util.makeCancelable(
-        new Promise(resolve => {
-          const state = {
-            lineNums: {left: 0, right: 0},
-            chunkIndex: 0,
-          };
+      new Promise(resolve => {
+        const state = {
+          lineNums: {left: 0, right: 0},
+          chunkIndex: 0,
+        };
 
-          chunks = this._splitLargeChunks(chunks);
-          chunks = this._splitCommonChunksWithKeyLocations(chunks);
+        chunks = this._splitLargeChunks(chunks);
+        chunks = this._splitCommonChunksWithKeyLocations(chunks);
 
-          let currentBatch = 0;
-          const nextStep = () => {
-            if (this._isScrolling) {
-              this._nextStepHandle = this.async(nextStep, 100);
-              return;
-            }
-            // If we are done, resolve the promise.
-            if (state.chunkIndex >= chunks.length) {
-              resolve();
-              this._nextStepHandle = null;
-              return;
-            }
+        let currentBatch = 0;
+        const nextStep = () => {
+          if (this._isScrolling) {
+            this._nextStepHandle = this.async(nextStep, 100);
+            return;
+          }
+          // If we are done, resolve the promise.
+          if (state.chunkIndex >= chunks.length) {
+            resolve();
+            this._nextStepHandle = null;
+            return;
+          }
 
-            // Process the next chunk and incorporate the result.
-            const stateUpdate = this._processNext(state, chunks);
-            for (const group of stateUpdate.groups) {
-              this.push('groups', group);
-              currentBatch += group.lines.length;
-            }
-            state.lineNums.left += stateUpdate.lineDelta.left;
-            state.lineNums.right += stateUpdate.lineDelta.right;
+          // Process the next chunk and incorporate the result.
+          const stateUpdate = this._processNext(state, chunks);
+          for (const group of stateUpdate.groups) {
+            this.push('groups', group);
+            currentBatch += group.lines.length;
+          }
+          state.lineNums.left += stateUpdate.lineDelta.left;
+          state.lineNums.right += stateUpdate.lineDelta.right;
 
-            // Increment the index and recurse.
-            state.chunkIndex = stateUpdate.newChunkIndex;
-            if (currentBatch >= this._asyncThreshold) {
-              currentBatch = 0;
-              this._nextStepHandle = this.async(nextStep, 1);
-            } else {
-              nextStep.call(this);
-            }
-          };
+          // Increment the index and recurse.
+          state.chunkIndex = stateUpdate.newChunkIndex;
+          if (currentBatch >= this._asyncThreshold) {
+            currentBatch = 0;
+            this._nextStepHandle = this.async(nextStep, 1);
+          } else {
+            nextStep.call(this);
+          }
+        };
 
-          nextStep.call(this);
-        }));
-    return this._processPromise
-        .finally(() => { this._processPromise = null; });
+        nextStep.call(this);
+      })
+    );
+    return this._processPromise.finally(() => {
+      this._processPromise = null;
+    });
   }
 
   /**
    * Cancel any jobs that are running.
    */
   cancel() {
-    if (this._nextStepHandle != null) {
+    if (this._nextStepHandle !== null) {
       this.cancelAsync(this._nextStepHandle);
       this._nextStepHandle = null;
     }
@@ -230,14 +223,12 @@
 
   /**
    * Process the next uncollapsible chunk, or the next collapsible chunks.
-   *
-   * @param {!Object} state
-   * @param {!Array<!Object>} chunks
-   * @return {{lineDelta: {left: number, right: number}, groups: !Array<!Object>, newChunkIndex: number}}
    */
-  _processNext(state, chunks) {
-    const firstUncollapsibleChunkIndex =
-        this._firstUncollapsibleChunkIndex(chunks, state.chunkIndex);
+  _processNext(state: State, chunks: DiffContent[]) {
+    const firstUncollapsibleChunkIndex = this._firstUncollapsibleChunkIndex(
+      chunks,
+      state.chunkIndex
+    );
     if (firstUncollapsibleChunkIndex === state.chunkIndex) {
       const chunk = chunks[state.chunkIndex];
       return {
@@ -245,34 +236,44 @@
           left: this._linesLeft(chunk).length,
           right: this._linesRight(chunk).length,
         },
-        groups: [this._chunkToGroup(
-            chunk, state.lineNums.left + 1, state.lineNums.right + 1)],
+        groups: [
+          this._chunkToGroup(
+            chunk,
+            state.lineNums.left + 1,
+            state.lineNums.right + 1
+          ),
+        ],
         newChunkIndex: state.chunkIndex + 1,
       };
     }
 
     return this._processCollapsibleChunks(
-        state, chunks, firstUncollapsibleChunkIndex);
+      state,
+      chunks,
+      firstUncollapsibleChunkIndex
+    );
   }
 
-  _linesLeft(chunk) {
+  _linesLeft(chunk: DiffContent) {
     return chunk.ab || chunk.a || [];
   }
 
-  _linesRight(chunk) {
+  _linesRight(chunk: DiffContent) {
     return chunk.ab || chunk.b || [];
   }
 
-  _firstUncollapsibleChunkIndex(chunks, offset) {
+  _firstUncollapsibleChunkIndex(chunks: DiffContent[], offset: number) {
     let chunkIndex = offset;
-    while (chunkIndex < chunks.length &&
-        this._isCollapsibleChunk(chunks[chunkIndex])) {
+    while (
+      chunkIndex < chunks.length &&
+      this._isCollapsibleChunk(chunks[chunkIndex])
+    ) {
       chunkIndex++;
     }
     return chunkIndex;
   }
 
-  _isCollapsibleChunk(chunk) {
+  _isCollapsibleChunk(chunk: DiffContent) {
     return (chunk.ab || chunk.common) && !chunk.keyLocation;
   }
 
@@ -280,36 +281,38 @@
    * Process a stretch of collapsible chunks.
    *
    * Outputs up to three groups:
-   *  1) Visible context before the hidden common code, unless it's the
-   *     very beginning of the file.
-   *  2) Context hidden behind a context bar, unless empty.
-   *  3) Visible context after the hidden common code, unless it's the very
-   *     end of the file.
-   *
-   * @param {!Object} state
-   * @param {!Array<Object>} chunks
-   * @param {number} firstUncollapsibleChunkIndex
-   * @return {{lineDelta: {left: number, right: number}, groups: !Array<!Object>, newChunkIndex: number}}
+   * 1) Visible context before the hidden common code, unless it's the
+   * very beginning of the file.
+   * 2) Context hidden behind a context bar, unless empty.
+   * 3) Visible context after the hidden common code, unless it's the very
+   * end of the file.
    */
   _processCollapsibleChunks(
-      state, chunks, firstUncollapsibleChunkIndex) {
+    state: State,
+    chunks: DiffContent[],
+    firstUncollapsibleChunkIndex: number
+  ) {
     const collapsibleChunks = chunks.slice(
-        state.chunkIndex, firstUncollapsibleChunkIndex);
+      state.chunkIndex,
+      firstUncollapsibleChunkIndex
+    );
     const lineCount = collapsibleChunks.reduce(
-        (sum, chunk) => sum + this._commonChunkLength(chunk), 0);
+      (sum, chunk) => sum + this._commonChunkLength(chunk),
+      0
+    );
 
     let groups = this._chunksToGroups(
-        collapsibleChunks,
-        state.lineNums.left + 1,
-        state.lineNums.right + 1);
+      collapsibleChunks,
+      state.lineNums.left + 1,
+      state.lineNums.right + 1
+    );
 
     if (this.context !== WHOLE_FILE) {
       const hiddenStart = state.chunkIndex === 0 ? 0 : this.context;
-      const hiddenEnd = lineCount - (
-        firstUncollapsibleChunkIndex === chunks.length ?
-          0 : this.context);
-      groups = hideInContextControl(
-          groups, hiddenStart, hiddenEnd);
+      const hiddenEnd =
+        lineCount -
+        (firstUncollapsibleChunkIndex === chunks.length ? 0 : this.context);
+      groups = hideInContextControl(groups, hiddenStart, hiddenEnd);
     }
 
     return {
@@ -322,21 +325,21 @@
     };
   }
 
-  _commonChunkLength(chunk) {
-    console.assert(chunk.ab || chunk.common);
+  _commonChunkLength(chunk: DiffContent) {
+    console.assert(!!chunk.ab || !!chunk.common);
     console.assert(
-        !chunk.a || (chunk.b && chunk.a.length === chunk.b.length),
-        `common chunk needs same number of a and b lines: `, chunk);
+      !chunk.a || (!!chunk.b && chunk.a.length === chunk.b.length),
+      'common chunk needs same number of a and b lines: ',
+      chunk
+    );
     return this._linesLeft(chunk).length;
   }
 
-  /**
-   * @param {!Array<!Object>} chunks
-   * @param {number} offsetLeft
-   * @param {number} offsetRight
-   * @return {!Array<!Object>} (GrDiffGroup)
-   */
-  _chunksToGroups(chunks, offsetLeft, offsetRight) {
+  _chunksToGroups(
+    chunks: DiffContent[],
+    offsetLeft: number,
+    offsetRight: number
+  ): GrDiffGroup[] {
     return chunks.map(chunk => {
       const group = this._chunkToGroup(chunk, offsetLeft, offsetRight);
       const chunkLength = this._commonChunkLength(chunk);
@@ -346,76 +349,83 @@
     });
   }
 
-  /**
-   * @param {!Object} chunk
-   * @param {number} offsetLeft
-   * @param {number} offsetRight
-   * @return {!Object} (GrDiffGroup)
-   */
-  _chunkToGroup(chunk, offsetLeft, offsetRight) {
+  _chunkToGroup(
+    chunk: DiffContent,
+    offsetLeft: number,
+    offsetRight: number
+  ): GrDiffGroup {
     const type = chunk.ab ? GrDiffGroupType.BOTH : GrDiffGroupType.DELTA;
     const lines = this._linesFromChunk(chunk, offsetLeft, offsetRight);
     const group = new GrDiffGroup(type, lines);
-    group.keyLocation = chunk.keyLocation;
-    group.dueToRebase = chunk.due_to_rebase;
-    group.ignoredWhitespaceOnly = chunk.common;
+    group.keyLocation = !!chunk.keyLocation;
+    group.dueToRebase = !!chunk.due_to_rebase;
+    group.ignoredWhitespaceOnly = !!chunk.common;
     return group;
   }
 
-  _linesFromChunk(chunk, offsetLeft, offsetRight) {
+  _linesFromChunk(chunk: DiffContent, offsetLeft: number, offsetRight: number) {
     if (chunk.ab) {
-      return chunk.ab.map((row, i) => this._lineFromRow(
-          GrDiffLineType.BOTH, offsetLeft, offsetRight, row, i));
+      return chunk.ab.map((row, i) =>
+        this._lineFromRow(GrDiffLineType.BOTH, offsetLeft, offsetRight, row, i)
+      );
     }
-    let lines = [];
+    let lines: GrDiffLine[] = [];
     if (chunk.a) {
       // Avoiding a.push(...b) because that causes callstack overflows for
       // large b, which can occur when large files are added removed.
-      lines = lines.concat(this._linesFromRows(
-          GrDiffLineType.REMOVE, chunk.a, offsetLeft,
-          chunk[DiffHighlights.REMOVED]));
+      lines = lines.concat(
+        this._linesFromRows(
+          GrDiffLineType.REMOVE,
+          chunk.a,
+          offsetLeft,
+          chunk.edit_a
+        )
+      );
     }
     if (chunk.b) {
       // Avoiding a.push(...b) because that causes callstack overflows for
       // large b, which can occur when large files are added removed.
-      lines = lines.concat(this._linesFromRows(
-          GrDiffLineType.ADD, chunk.b, offsetRight,
-          chunk[DiffHighlights.ADDED]));
+      lines = lines.concat(
+        this._linesFromRows(
+          GrDiffLineType.ADD,
+          chunk.b,
+          offsetRight,
+          chunk.edit_b
+        )
+      );
     }
     return lines;
   }
 
-  /**
-   * @param {string} lineType (GrDiffLineType)
-   * @param {!Array<string>} rows
-   * @param {number} offset
-   * @param {?Array<!Gerrit.IntralineInfo>=} opt_intralineInfos
-   * @return {!Array<!Object>} (GrDiffLine)
-   */
-  _linesFromRows(lineType, rows, offset, opt_intralineInfos) {
-    const grDiffHighlights = opt_intralineInfos ?
-      this._convertIntralineInfos(rows, opt_intralineInfos) : undefined;
-    return rows.map((row, i) => this._lineFromRow(
-        lineType, offset, offset, row, i, grDiffHighlights));
+  _linesFromRows(
+    lineType: GrDiffLineType,
+    rows: string[],
+    offset: number,
+    intralineInfos?: number[][]
+  ): GrDiffLine[] {
+    const grDiffHighlights = intralineInfos
+      ? this._convertIntralineInfos(rows, intralineInfos)
+      : undefined;
+    return rows.map((row, i) =>
+      this._lineFromRow(lineType, offset, offset, row, i, grDiffHighlights)
+    );
   }
 
-  /**
-   * @param {string} type (GrDiffLineType)
-   * @param {number} offsetLeft
-   * @param {number} offsetRight
-   * @param {string} row
-   * @param {number} i
-   * @param {!Array<!Object>=} opt_highlights
-   * @return {!Object} (GrDiffLine)
-   */
-  _lineFromRow(type, offsetLeft, offsetRight, row, i, opt_highlights) {
+  _lineFromRow(
+    type: GrDiffLineType,
+    offsetLeft: number,
+    offsetRight: number,
+    row: string,
+    i: number,
+    highlights: Highlights[] = []
+  ): GrDiffLine {
     const line = new GrDiffLine(type);
     line.text = row;
     if (type !== GrDiffLineType.ADD) line.beforeNumber = offsetLeft + i;
     if (type !== GrDiffLineType.REMOVE) line.afterNumber = offsetRight + i;
-    if (opt_highlights) {
+    if (highlights) {
       line.hasIntralineInfo = true;
-      line.highlights = opt_highlights.filter(hl => hl.contentIndex === i);
+      line.highlights = highlights.filter(hl => hl.contentIndex === i);
     } else {
       line.hasIntralineInfo = false;
     }
@@ -441,10 +451,10 @@
    * into 2 chunks, one max sized one and the rest (for reasons that are
    * unclear to me).
    *
-   * @param {!Array<!Gerrit.DiffChunk>} chunks Chunks as returned from the server
-   * @return {!Array<!Gerrit.DiffChunk>} Finer grained chunks.
+   * @param chunks Chunks as returned from the server
+   * @return Finer grained chunks.
    */
-  _splitLargeChunks(chunks) {
+  _splitLargeChunks(chunks: DiffContent[]): DiffContent[] {
     const newChunks = [];
 
     for (const chunk of chunks) {
@@ -476,10 +486,10 @@
    * the selected context, treat them as separate chunks within the model so
    * that the content (and context surrounding it) renders correctly.
    *
-   * @param {!Array<!Object>} chunks DiffContents as returned from server.
-   * @return {!Array<!Object>} Finer grained DiffContents.
+   * @param chunks DiffContents as returned from server.
+   * @return Finer grained DiffContents.
    */
-  _splitCommonChunksWithKeyLocations(chunks) {
+  _splitCommonChunksWithKeyLocations(chunks: DiffContent[]): DiffContent[] {
     const result = [];
     let leftLineNum = 1;
     let rightLineNum = 1;
@@ -497,32 +507,45 @@
         continue;
       }
 
-      if (chunk.common && chunk.a.length != chunk.b.length) {
+      if (chunk.common && chunk.a!.length !== chunk.b!.length) {
         throw new Error(
-            'DiffContent with common=true must always have equal length');
+          'DiffContent with common=true must always have equal length'
+        );
       }
       const numLines = this._commonChunkLength(chunk);
       const chunkEnds = this._findChunkEndsAtKeyLocations(
-          numLines, leftLineNum, rightLineNum);
+        numLines,
+        leftLineNum,
+        rightLineNum
+      );
       leftLineNum += numLines;
       rightLineNum += numLines;
 
       if (chunk.ab) {
-        result.push(...this._splitAtChunkEnds(chunk.ab, chunkEnds)
-            .map(({lines, keyLocation}) => {
+        result.push(
+          ...this._splitAtChunkEnds(chunk.ab, chunkEnds).map(
+            ({lines, keyLocation}) => {
               return {
                 ...chunk,
                 ab: lines,
                 keyLocation,
               };
-            }));
+            }
+          )
+        );
       } else if (chunk.common) {
-        const aChunks = this._splitAtChunkEnds(chunk.a, chunkEnds);
-        const bChunks = this._splitAtChunkEnds(chunk.b, chunkEnds);
-        result.push(...aChunks.map(({lines, keyLocation}, i) => {
-          return {
-            ...chunk, a: lines, b: bChunks[i].lines, keyLocation};
-        }));
+        const aChunks = this._splitAtChunkEnds(chunk.a!, chunkEnds);
+        const bChunks = this._splitAtChunkEnds(chunk.b!, chunkEnds);
+        result.push(
+          ...aChunks.map(({lines, keyLocation}, i) => {
+            return {
+              ...chunk,
+              a: lines,
+              b: bChunks[i].lines,
+              keyLocation,
+            };
+          })
+        );
       }
     }
 
@@ -530,16 +553,22 @@
   }
 
   /**
-   * @return {!Array<{offset: number, keyLocation: boolean}>} Offsets of the
-   *   new chunk ends, including whether it's a key location.
+   * @return Offsets of the new chunk ends, including whether it's a key
+   * location.
    */
-  _findChunkEndsAtKeyLocations(numLines, leftOffset, rightOffset) {
+  _findChunkEndsAtKeyLocations(
+    numLines: number,
+    leftOffset: number,
+    rightOffset: number
+  ): ChunkEnd[] {
     const result = [];
     let lastChunkEnd = 0;
-    for (let i=0; i<numLines; i++) {
+    for (let i = 0; i < numLines; i++) {
       // If this line should not be collapsed.
-      if (this.keyLocations[DiffSide.LEFT][leftOffset + i] ||
-          this.keyLocations[DiffSide.RIGHT][rightOffset + i]) {
+      if (
+        this.keyLocations[DiffSide.LEFT][leftOffset + i] ||
+        this.keyLocations[DiffSide.RIGHT][rightOffset + i]
+      ) {
         // If any lines have been accumulated into the chunk leading up to
         // this non-collapse line, then add them as a chunk and start a new
         // one.
@@ -560,12 +589,14 @@
     return result;
   }
 
-  _splitAtChunkEnds(lines, chunkEnds) {
+  _splitAtChunkEnds(lines: string[], chunkEnds: ChunkEnd[]) {
     const result = [];
     let lastChunkEndOffset = 0;
     for (const {offset, keyLocation} of chunkEnds) {
-      result.push(
-          {lines: lines.slice(lastChunkEndOffset, offset), keyLocation});
+      result.push({
+        lines: lines.slice(lastChunkEndOffset, offset),
+        keyLocation,
+      });
       lastChunkEndOffset = offset;
     }
     return result;
@@ -574,12 +605,11 @@
   /**
    * Converts `IntralineInfo`s return by the API to `GrLineHighlights` used
    * for rendering.
-   *
-   * @param {!Array<string>} rows
-   * @param {!Array<!Gerrit.IntralineInfo>} intralineInfos
-   * @return {!Array<!Object>} (Highlights[] from GrDiffLine)
    */
-  _convertIntralineInfos(rows, intralineInfos) {
+  _convertIntralineInfos(
+    rows: string[],
+    intralineInfos: number[][]
+  ): Highlights[] {
     let rowIndex = 0;
     let idx = 0;
     const normalized = [];
@@ -595,7 +625,7 @@
         idx++;
         j++;
       }
-      let lineHighlight = {
+      let lineHighlight: Highlights = {
         contentIndex: rowIndex,
         startIndex: idx,
       };
@@ -625,12 +655,9 @@
    * If a group is an addition or a removal, break it down into smaller groups
    * of that type using the MAX_GROUP_SIZE. If the group is a shared chunk
    * or a delta it is returned as the single element of the result array.
-   *
-   * @param {!Gerrit.DiffChunk} chunk A raw chunk from a diff response.
-   * @return {!Array<!Array<!Object>>}
    */
-  _breakdownChunk(chunk) {
-    let key = null;
+  _breakdownChunk(chunk: DiffContent): DiffContent[] {
+    let key: 'a' | 'b' | 'ab' | null = null;
     if (chunk.a && !chunk.b) {
       key = 'a';
     } else if (chunk.b && !chunk.a) {
@@ -639,31 +666,31 @@
       key = 'ab';
     }
 
-    if (!key) { return [chunk]; }
+    if (!key) {
+      return [chunk];
+    }
 
-    return this._breakdown(chunk[key], MAX_GROUP_SIZE)
-        .map(subChunkLines => {
-          const subChunk = {};
-          subChunk[key] = subChunkLines;
-          if (chunk.due_to_rebase) {
-            subChunk.due_to_rebase = true;
-          }
-          return subChunk;
-        });
+    return this._breakdown(chunk[key]!, MAX_GROUP_SIZE).map(subChunkLines => {
+      const subChunk: DiffContent = {};
+      subChunk[key!] = subChunkLines;
+      if (chunk.due_to_rebase) {
+        subChunk.due_to_rebase = true;
+      }
+      return subChunk;
+    });
   }
 
   /**
    * Given an array and a size, return an array of arrays where no inner array
    * is larger than that size, preserving the original order.
-   *
-   * @param {!Array<T>} array
-   * @param {number} size
-   * @return {!Array<!Array<T>>}
-   * @template T
    */
-  _breakdown(array, size) {
-    if (!array.length) { return []; }
-    if (array.length < size) { return [array]; }
+  _breakdown<T>(array: T[], size: number): T[][] {
+    if (!array.length) {
+      return [];
+    }
+    if (array.length < size) {
+      return [array];
+    }
 
     const head = array.slice(0, array.length - size);
     const tail = array.slice(array.length - size);
@@ -672,4 +699,8 @@
   }
 }
 
-customElements.define(GrDiffProcessor.is, GrDiffProcessor);
+declare global {
+  interface HTMLElementTagNameMap {
+    'gr-diff-processor': GrDiffProcessor;
+  }
+}