tsconfig: Enable noUncheckedIndexedAccess.

Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
Anders Kaseorg 2024-05-23 15:02:38 -07:00
parent 4e91572c96
commit 804c3706ff
61 changed files with 210 additions and 205 deletions

View File

@ -26,6 +26,7 @@
"forceConsistentCasingInFileNames": true, "forceConsistentCasingInFileNames": true,
"isolatedModules": true, "isolatedModules": true,
"noImplicitOverride": true, "noImplicitOverride": true,
"noUncheckedIndexedAccess": true,
/* Additional checks */ /* Additional checks */
"noUnusedLocals": true, "noUnusedLocals": true,

View File

@ -215,9 +215,9 @@ export function process_fenced_code(content: string): string {
consume_line = function consume_line(output_lines: string[], line: string) { consume_line = function consume_line(output_lines: string[], line: string) {
const match = fence_re.exec(line); const match = fence_re.exec(line);
if (match) { if (match) {
const fence = match[1]; const fence = match[1]!;
const lang = match[3]; const lang = match[3]!;
const header = match[5]; const header = match[5]!;
const handler = handler_for_fence(output_lines, fence, lang, header); const handler = handler_for_fence(output_lines, fence, lang, header);
handler_stack.push(handler); handler_stack.push(handler);
} else { } else {
@ -255,7 +255,7 @@ export function get_unused_fence(content: string): string {
let match; let match;
fence_length_re.lastIndex = 0; fence_length_re.lastIndex = 0;
while ((match = fence_length_re.exec(content)) !== null) { while ((match = fence_length_re.exec(content)) !== null) {
length = Math.max(length, match[1].length + 1); length = Math.max(length, match[1]!.length + 1);
} }
return "`".repeat(length); return "`".repeat(length);
} }

View File

@ -68,12 +68,12 @@ export function last_prefix_match(prefix: string, words: string[]): number | nul
let found = false; let found = false;
while (left < right) { while (left < right) {
const mid = Math.floor((left + right) / 2); const mid = Math.floor((left + right) / 2);
if (words[mid].startsWith(prefix)) { if (words[mid]!.startsWith(prefix)) {
// Note that left can never be 0 if `found` is true, // Note that left can never be 0 if `found` is true,
// since it is incremented at least once here. // since it is incremented at least once here.
left = mid + 1; left = mid + 1;
found = true; found = true;
} else if (words[mid] < prefix) { } else if (words[mid]! < prefix) {
left = mid + 1; left = mid + 1;
} else { } else {
right = mid; right = mid;

View File

@ -19,12 +19,12 @@ export function launch(): void {
const zulip_version_clipboard = new ClipboardJS("#about-zulip .fa-copy.zulip-version"); const zulip_version_clipboard = new ClipboardJS("#about-zulip .fa-copy.zulip-version");
zulip_version_clipboard.on("success", () => { zulip_version_clipboard.on("success", () => {
show_copied_confirmation($("#about-zulip .fa-copy.zulip-version")[0]); show_copied_confirmation($("#about-zulip .fa-copy.zulip-version")[0]!);
}); });
const zulip_merge_base_clipboard = new ClipboardJS("#about-zulip .fa-copy.zulip-merge-base"); const zulip_merge_base_clipboard = new ClipboardJS("#about-zulip .fa-copy.zulip-merge-base");
zulip_merge_base_clipboard.on("success", () => { zulip_merge_base_clipboard.on("success", () => {
show_copied_confirmation($("#about-zulip .fa-copy.zulip-merge-base")[0]); show_copied_confirmation($("#about-zulip .fa-copy.zulip-merge-base")[0]!);
}); });
} }

View File

@ -22,6 +22,6 @@ export function update_notification_sound_source(
if (notification_sound !== "none") { if (notification_sound !== "none") {
// Load it so that it is ready to be played; without this the old sound // Load it so that it is ready to be played; without this the old sound
// is played. // is played.
$container_elem[0].load(); $container_elem[0]!.load();
} }
} }

View File

@ -158,7 +158,7 @@ export function update_discount_details(
} }
export function is_valid_input($elem: JQuery<HTMLFormElement>): boolean { export function is_valid_input($elem: JQuery<HTMLFormElement>): boolean {
return $elem[0].checkValidity(); return $elem[0]!.checkValidity();
} }
export function redirect_to_billing_with_successful_upgrade(billing_base_url: string): void { export function redirect_to_billing_with_successful_upgrade(billing_base_url: string): void {

View File

@ -279,7 +279,7 @@ export class Typeahead<ItemType extends string | object> {
} }
select(e?: JQuery.ClickEvent | JQuery.KeyUpEvent | JQuery.KeyDownEvent): this { select(e?: JQuery.ClickEvent | JQuery.KeyUpEvent | JQuery.KeyDownEvent): this {
const val = this.values.get(this.$menu.find(".active")[0]); const val = this.values.get(this.$menu.find(".active")[0]!);
assert(val !== undefined); assert(val !== undefined);
if (this.input_element.type === "contenteditable") { if (this.input_element.type === "contenteditable") {
this.input_element.$element this.input_element.$element
@ -295,8 +295,8 @@ export class Typeahead<ItemType extends string | object> {
const [from, to_before, to_after] = get_string_diff(element_val, after_text); const [from, to_before, to_after] = get_string_diff(element_val, after_text);
const replacement = after_text.slice(from, to_after); const replacement = after_text.slice(from, to_after);
// select / highlight the minimal text to be replaced // select / highlight the minimal text to be replaced
this.input_element.$element[0].setSelectionRange(from, to_before); this.input_element.$element[0]!.setSelectionRange(from, to_before);
insertTextIntoField(this.input_element.$element[0], replacement); insertTextIntoField(this.input_element.$element[0]!, replacement);
this.input_element.$element.trigger("change"); this.input_element.$element.trigger("change");
} }
@ -304,7 +304,7 @@ export class Typeahead<ItemType extends string | object> {
} }
set_value(): void { set_value(): void {
const val = this.values.get(this.$menu.find(".active")[0]); const val = this.values.get(this.$menu.find(".active")[0]!);
assert(typeof val === "string"); assert(typeof val === "string");
if (this.input_element.type === "contenteditable") { if (this.input_element.type === "contenteditable") {
this.input_element.$element.text(val); this.input_element.$element.text(val);
@ -340,7 +340,7 @@ export class Typeahead<ItemType extends string | object> {
// We don't need tippy to position typeaheads which already know where they should be. // We don't need tippy to position typeaheads which already know where they should be.
return this; return this;
} }
this.instance = tippy.default(this.input_element.$element[0], { this.instance = tippy.default(this.input_element.$element[0]!, {
// Lets typeahead take the width needed to fit the content // Lets typeahead take the width needed to fit the content
// and wraps it if it overflows the visible container. // and wraps it if it overflows the visible container.
maxWidth: "none", maxWidth: "none",
@ -371,7 +371,7 @@ export class Typeahead<ItemType extends string | object> {
interactive: true, interactive: true,
appendTo: () => document.body, appendTo: () => document.body,
showOnCreate: true, showOnCreate: true,
content: this.$container[0], content: this.$container[0]!,
// We expect the typeahead creator to handle when to hide / show the typeahead. // We expect the typeahead creator to handle when to hide / show the typeahead.
trigger: "manual", trigger: "manual",
arrow: false, arrow: false,
@ -449,7 +449,7 @@ export class Typeahead<ItemType extends string | object> {
render(final_items: ItemType[], matching_items: ItemType[]): this { render(final_items: ItemType[], matching_items: ItemType[]): this {
const $items: JQuery[] = final_items.map((item) => { const $items: JQuery[] = final_items.map((item) => {
const $i = $(ITEM_HTML); const $i = $(ITEM_HTML);
this.values.set($i[0], item); this.values.set($i[0]!, item);
const item_html = this.highlighter_html(item, this.query) ?? ""; const item_html = this.highlighter_html(item, this.query) ?? "";
const $item_html = $i.find("a").html(item_html); const $item_html = $i.find("a").html(item_html);
@ -461,7 +461,7 @@ export class Typeahead<ItemType extends string | object> {
return $i; return $i;
}); });
$items[0].addClass("active"); $items[0]!.addClass("active");
this.$menu.empty().append($items); this.$menu.empty().append($items);
return this; return this;
} }
@ -621,12 +621,12 @@ export class Typeahead<ItemType extends string | object> {
this.select(e); this.select(e);
if (this.input_element.$element[0].id === "stream_message_recipient_topic") { if (this.input_element.$element[0]!.id === "stream_message_recipient_topic") {
assert(this.input_element.type === "input"); assert(this.input_element.type === "input");
// Move the cursor to the end of the topic // Move the cursor to the end of the topic
const topic_length = this.input_element.$element.val()!.length; const topic_length = this.input_element.$element.val()!.length;
this.input_element.$element[0].selectionStart = topic_length; this.input_element.$element[0]!.selectionStart = topic_length;
this.input_element.$element[0].selectionEnd = topic_length; this.input_element.$element[0]!.selectionEnd = topic_length;
} }
break; break;
@ -653,7 +653,7 @@ export class Typeahead<ItemType extends string | object> {
// when shift (keycode 16) + tabbing to the topic field // when shift (keycode 16) + tabbing to the topic field
if ( if (
pseudo_keycode === 16 && pseudo_keycode === 16 &&
this.input_element.$element[0].id === "stream_message_recipient_topic" this.input_element.$element[0]!.id === "stream_message_recipient_topic"
) { ) {
return; return;
} }

View File

@ -170,7 +170,7 @@ export class BuddyList extends BuddyListConf {
// This will default to "bottom" placement for this tooltip. // This will default to "bottom" placement for this tooltip.
placement = "auto"; placement = "auto";
} }
tippy.default($elem[0], { tippy.default($elem[0]!, {
// Because the buddy list subheadings are potential click targets // Because the buddy list subheadings are potential click targets
// for purposes having nothing to do with the subscriber count // for purposes having nothing to do with the subscriber count
// (collapsing/expanding), we delay showing the tooltip until the // (collapsing/expanding), we delay showing the tooltip until the
@ -765,7 +765,7 @@ export class BuddyList extends BuddyListConf {
const elem = scroll_util const elem = scroll_util
.get_scroll_element($(this.scroll_container_selector)) .get_scroll_element($(this.scroll_container_selector))
.expectOne()[0]; .expectOne()[0]!;
// Add a fudge factor. // Add a fudge factor.
height += 10; height += 10;

View File

@ -62,7 +62,7 @@ export function claim_colors(subs: {color: string}[]): void {
} }
export function pick_color(): string { export function pick_color(): string {
const color = unused_colors[0]; const color = unused_colors[0]!;
claim_color(color); claim_color(color);

View File

@ -108,7 +108,7 @@ function set_password_toggle_label(
): void { ): void {
$(password_selector).attr("aria-label", label); $(password_selector).attr("aria-label", label);
if (tippy_tooltips) { if (tippy_tooltips) {
const element: tippy.ReferenceElement = $(password_selector)[0]; const element: tippy.ReferenceElement = $(password_selector)[0]!;
const tippy_instance = element._tippy ?? tippy.default(element); const tippy_instance = element._tippy ?? tippy.default(element);
tippy_instance.setContent(label); tippy_instance.setContent(label);
} else { } else {

View File

@ -82,7 +82,7 @@ export function toggle(opts: {
meta.idx = idx; meta.idx = idx;
if (opts.callback) { if (opts.callback) {
opts.callback(opts.values[idx].label, opts.values[idx].key); opts.callback(opts.values[idx]!.label, opts.values[idx]!.key);
} }
if (!opts.child_wants_focus) { if (!opts.child_wants_focus) {
@ -162,7 +162,7 @@ export function toggle(opts: {
value() { value() {
if (meta.idx >= 0) { if (meta.idx >= 0) {
return opts.values[meta.idx].label; return opts.values[meta.idx]!.label;
} }
/* istanbul ignore next */ /* istanbul ignore next */
return undefined; return undefined;

View File

@ -213,7 +213,7 @@ export function update_rendered_message_groups(
// the other code takes advantage of blocks beneath recipient bars. // the other code takes advantage of blocks beneath recipient bars.
for (const message_group of message_groups) { for (const message_group of message_groups) {
const $elt = get_element(message_group); const $elt = get_element(message_group);
const first_message = message_group.message_containers[0].msg; const first_message = message_group.message_containers[0]!.msg;
const should_fade = compose_fade_helper.should_fade_message(first_message); const should_fade = compose_fade_helper.should_fade_message(first_message);
change_fade_state($elt, should_fade); change_fade_state($elt, should_fade);
} }

View File

@ -314,7 +314,7 @@ function on_hidden_callback(): void {
// Always move focus to the topic input even if it's not empty, // Always move focus to the topic input even if it's not empty,
// since it's likely the user will want to update the topic // since it's likely the user will want to update the topic
// after updating the stream. // after updating the stream.
ui_util.place_caret_at_end($("input#stream_message_recipient_topic")[0]); ui_util.place_caret_at_end($("input#stream_message_recipient_topic")[0]!);
} else { } else {
if (compose_state.private_message_recipient().length === 0) { if (compose_state.private_message_recipient().length === 0) {
$("#private_message_recipient").trigger("focus").trigger("select"); $("#private_message_recipient").trigger("focus").trigger("select");

View File

@ -98,9 +98,9 @@ export function insert_and_scroll_into_view(
replace_all = false, replace_all = false,
): void { ): void {
if (replace_all) { if (replace_all) {
setFieldText($textarea[0], content); setFieldText($textarea[0]!, content);
} else { } else {
insertTextIntoField($textarea[0], content); insertTextIntoField($textarea[0]!, content);
} }
// Blurring and refocusing ensures the cursor / selection is in view // Blurring and refocusing ensures the cursor / selection is in view
// in chromium browsers. // in chromium browsers.
@ -275,7 +275,7 @@ export function replace_syntax(
// for details. // for details.
const old_text = $textarea.val(); const old_text = $textarea.val();
replaceFieldText($textarea[0], old_syntax, () => new_syntax, "after-replacement"); replaceFieldText($textarea[0]!, old_syntax, () => new_syntax, "after-replacement");
const new_text = $textarea.val(); const new_text = $textarea.val();
// When replacing content in a textarea, we need to move the cursor // When replacing content in a textarea, we need to move the cursor

View File

@ -250,7 +250,7 @@ function handle_bulleting_or_numbering(
if (bulleted_numbered_list_util.strip_bullet(previous_line) === "") { if (bulleted_numbered_list_util.strip_bullet(previous_line) === "") {
// below we select and replace the last 2 characters in the textarea before // below we select and replace the last 2 characters in the textarea before
// the cursor - the bullet syntax - with an empty string // the cursor - the bullet syntax - with an empty string
$textarea[0].setSelectionRange($textarea.caret() - 2, $textarea.caret()); $textarea[0]!.setSelectionRange($textarea.caret() - 2, $textarea.caret());
compose_ui.insert_and_scroll_into_view("", $textarea); compose_ui.insert_and_scroll_into_view("", $textarea);
e.preventDefault(); e.preventDefault();
return; return;
@ -264,7 +264,7 @@ function handle_bulleting_or_numbering(
if (bulleted_numbered_list_util.strip_numbering(previous_line) === "") { if (bulleted_numbered_list_util.strip_numbering(previous_line) === "") {
// below we select then replaces the last few characters in the textarea before // below we select then replaces the last few characters in the textarea before
// the cursor - the numbering syntax - with an empty string // the cursor - the numbering syntax - with an empty string
$textarea[0].setSelectionRange( $textarea[0]!.setSelectionRange(
$textarea.caret() - previous_number_string.length - 2, $textarea.caret() - previous_number_string.length - 2,
$textarea.caret(), $textarea.caret(),
); );
@ -297,7 +297,7 @@ export function handle_enter($textarea: JQuery<HTMLTextAreaElement>, e: JQuery.K
// If the selectionStart and selectionEnd are not the same, that // If the selectionStart and selectionEnd are not the same, that
// means that some text was selected. // means that some text was selected.
if ($textarea[0].selectionStart !== $textarea[0].selectionEnd) { if ($textarea[0]!.selectionStart !== $textarea[0]!.selectionEnd) {
// Replace it with the newline, remembering to resize the // Replace it with the newline, remembering to resize the
// textarea if needed. // textarea if needed.
compose_ui.insert_and_scroll_into_view("\n", $textarea); compose_ui.insert_and_scroll_into_view("\n", $textarea);
@ -431,7 +431,7 @@ export function tokenize_compose_str(s: string): string {
case "_": case "_":
if (i === 0) { if (i === 0) {
return s; return s;
} else if (/[\s"'(/<[{]/.test(s[i - 1])) { } else if (/[\s"'(/<[{]/.test(s[i - 1]!)) {
return s.slice(i); return s.slice(i);
} }
break; break;
@ -775,7 +775,7 @@ export function get_candidates(
// We will likely want to extend this list to be more i18n-friendly. // We will likely want to extend this list to be more i18n-friendly.
const terminal_symbols = ",.;?!()[]> \"'\n\t"; const terminal_symbols = ",.;?!()[]> \"'\n\t";
if (rest !== "" && !terminal_symbols.includes(rest[0])) { if (rest !== "" && !terminal_symbols.includes(rest[0]!)) {
return []; return [];
} }
@ -1158,7 +1158,7 @@ export function content_typeahead_selected(
$textbox.caret(beginning.length); $textbox.caret(beginning.length);
compose_ui.autosize_textarea($textbox); compose_ui.autosize_textarea($textbox);
}; };
flatpickr.show_flatpickr(input_element.$element[0], on_timestamp_selection, timestamp); flatpickr.show_flatpickr(input_element.$element[0]!, on_timestamp_selection, timestamp);
return beginning + rest; return beginning + rest;
} }
} }

View File

@ -151,7 +151,7 @@ function get_message_height(elem: HTMLElement): number {
// This needs to be very fast. This function runs hundreds of times // This needs to be very fast. This function runs hundreds of times
// when displaying a message feed view that has hundreds of message // when displaying a message feed view that has hundreds of message
// history, which ideally should render in <100ms. // history, which ideally should render in <100ms.
return $(elem).find(".message_content")[0].scrollHeight; return $(elem).find(".message_content")[0]!.scrollHeight;
} }
export function hide_message_expander($row: JQuery): void { export function hide_message_expander($row: JQuery): void {

View File

@ -132,7 +132,7 @@ function select_div($div: JQuery, selection: Selection): void {
background: "#FFF", background: "#FFF",
}).attr("id", "copytempdiv"); }).attr("id", "copytempdiv");
$("body").append($div); $("body").append($div);
selection.selectAllChildren($div[0]); selection.selectAllChildren($div[0]!);
} }
function remove_div(_div: JQuery, ranges: Range[]): void { function remove_div(_div: JQuery, ranges: Range[]): void {
@ -591,7 +591,7 @@ function is_safe_url_paste_target($textarea: JQuery<HTMLTextAreaElement>): boole
// Look at the two characters before the start of the original // Look at the two characters before the start of the original
// range in search of the tell-tale `](` from existing Markdown // range in search of the tell-tale `](` from existing Markdown
// link syntax // link syntax
const possible_markdown_link_markers = $textarea[0].value.slice(range.start - 2, range.start); const possible_markdown_link_markers = $textarea[0]!.value.slice(range.start - 2, range.start);
if (possible_markdown_link_markers === "](") { if (possible_markdown_link_markers === "](") {
return false; return false;

View File

@ -367,7 +367,7 @@ function draft_notify(): void {
content: $t({defaultMessage: "Saved as draft"}), content: $t({defaultMessage: "Saved as draft"}),
arrow: true, arrow: true,
placement: "right", placement: "right",
})[0]; })[0]!;
instance.show(); instance.show();
function remove_instance(): void { function remove_instance(): void {
instance.destroy(); instance.destroy();

View File

@ -86,7 +86,7 @@ function zephyr_topic_name_match(message: Message & {type: "stream"}, operand: s
const m = /^(.*?)(?:\.d)*$/i.exec(operand); const m = /^(.*?)(?:\.d)*$/i.exec(operand);
// m should never be null because any string matches that regex. // m should never be null because any string matches that regex.
assert(m !== null); assert(m !== null);
const base_topic = m[1]; const base_topic = m[1]!;
let related_regexp; let related_regexp;
// Additionally, Zephyr users expect the empty instance and // Additionally, Zephyr users expect the empty instance and
@ -257,7 +257,7 @@ export class Filter {
constructor(terms: NarrowTerm[]) { constructor(terms: NarrowTerm[]) {
this._terms = this.fix_terms(terms); this._terms = this.fix_terms(terms);
if (this.has_operator("channel")) { if (this.has_operator("channel")) {
this._sub = stream_data.get_sub_by_name(this.operands("channel")[0]); this._sub = stream_data.get_sub_by_name(this.operands("channel")[0]!);
} }
} }
@ -724,7 +724,7 @@ export class Filter {
} }
is_non_huddle_pm(): boolean { is_non_huddle_pm(): boolean {
return this.has_operator("dm") && this.operands("dm")[0].split(",").length === 1; return this.has_operator("dm") && this.operands("dm")[0]!.split(",").length === 1;
} }
supports_collapsing_recipients(): boolean { supports_collapsing_recipients(): boolean {
@ -872,7 +872,7 @@ export class Filter {
"/#narrow/" + "/#narrow/" +
CHANNEL_SYNONYM + CHANNEL_SYNONYM +
"/" + "/" +
stream_data.name_to_slug(this.operands("channel")[0]) + stream_data.name_to_slug(this.operands("channel")[0]!) +
"/topic/" + "/topic/" +
this.operands("topic")[0] this.operands("topic")[0]
); );
@ -894,7 +894,7 @@ export class Filter {
"/#narrow/" + "/#narrow/" +
CHANNEL_SYNONYM + CHANNEL_SYNONYM +
"/" + "/" +
stream_data.name_to_slug(this.operands("channel")[0]) stream_data.name_to_slug(this.operands("channel")[0]!)
); );
case "is-dm": case "is-dm":
return "/#narrow/is/dm"; return "/#narrow/is/dm";
@ -911,7 +911,7 @@ export class Filter {
// TODO: It is ambiguous how we want to handle the 'sender' case, // TODO: It is ambiguous how we want to handle the 'sender' case,
// we may remove it in the future based on design decisions // we may remove it in the future based on design decisions
case "sender": case "sender":
return "/#narrow/sender/" + people.emails_to_slug(this.operands("sender")[0]); return "/#narrow/sender/" + people.emails_to_slug(this.operands("sender")[0]!);
} }
} }
@ -991,7 +991,7 @@ export class Filter {
(term_types.length === 2 && _.isEqual(term_types, ["dm", "near"])) || (term_types.length === 2 && _.isEqual(term_types, ["dm", "near"])) ||
(term_types.length === 1 && _.isEqual(term_types, ["dm"])) (term_types.length === 1 && _.isEqual(term_types, ["dm"]))
) { ) {
const emails = this.operands("dm")[0].split(","); const emails = this.operands("dm")[0]!.split(",");
const names = emails.map((email) => { const names = emails.map((email) => {
const person = people.get_by_email(email); const person = people.get_by_email(email);
if (!person) { if (!person) {
@ -1006,7 +1006,7 @@ export class Filter {
return util.format_array_as_list(names, "long", "conjunction"); return util.format_array_as_list(names, "long", "conjunction");
} }
if (term_types.length === 1 && _.isEqual(term_types, ["sender"])) { if (term_types.length === 1 && _.isEqual(term_types, ["sender"])) {
const email = this.operands("sender")[0]; const email = this.operands("sender")[0]!;
const user = people.get_by_email(email); const user = people.get_by_email(email);
let sender = email; let sender = email;
if (user) { if (user) {

View File

@ -25,7 +25,7 @@ export function show_flatpickr(
): flatpickr.Instance { ): flatpickr.Instance {
const $flatpickr_input = $<HTMLInputElement>("<input>").attr("id", "#timestamp_flatpickr"); const $flatpickr_input = $<HTMLInputElement>("<input>").attr("id", "#timestamp_flatpickr");
flatpickr_instance = flatpickr($flatpickr_input[0], { flatpickr_instance = flatpickr($flatpickr_input[0]!, {
mode: "single", mode: "single",
enableTime: true, enableTime: true,
clickOpens: false, clickOpens: false,

View File

@ -1,6 +1,6 @@
export function get_hash_category(hash?: string): string { export function get_hash_category(hash?: string): string {
// given "#channels/subscribed", returns "channels" // given "#channels/subscribed", returns "channels"
return hash ? hash.replace(/^#/, "").split(/\//)[0] : ""; return hash ? hash.replace(/^#/, "").split(/\//)[0]! : "";
} }
export function get_hash_section(hash?: string): string { export function get_hash_section(hash?: string): string {
@ -88,7 +88,7 @@ export function is_editing_stream(desired_stream_id: number): boolean {
// if the string casted to a number is valid, and another component // if the string casted to a number is valid, and another component
// after exists then it's a stream name/id pair. // after exists then it's a stream name/id pair.
const stream_id = Number.parseFloat(hash_components[1]); const stream_id = Number.parseFloat(hash_components[1]!);
return stream_id === desired_stream_id; return stream_id === desired_stream_id;
} }

View File

@ -164,7 +164,7 @@ export function parse_narrow(hash: string[]): NarrowTerm[] | undefined {
for (i = 1; i < hash.length; i += 2) { for (i = 1; i < hash.length; i += 2) {
// We don't construct URLs with an odd number of components, // We don't construct URLs with an odd number of components,
// but the user might write one. // but the user might write one.
let operator = internal_url.decodeHashComponent(hash[i]); let operator = internal_url.decodeHashComponent(hash[i]!);
// Do not parse further if empty operator encountered. // Do not parse further if empty operator encountered.
if (operator === "") { if (operator === "") {
break; break;

View File

@ -324,7 +324,7 @@ function insert_dms(keys_to_insert: string[]): void {
} }
if (keys_to_insert.includes(key)) { if (keys_to_insert.includes(key)) {
const $previous_row = get_row_from_conversation_key(sorted_keys[i - 1]); const $previous_row = get_row_from_conversation_key(sorted_keys[i - 1]!);
$previous_row.after($(render_inbox_row(dms_dict.get(key)))); $previous_row.after($(render_inbox_row(dms_dict.get(key))));
} }
} }
@ -462,7 +462,7 @@ function insert_stream(
if (stream_index === 0) { if (stream_index === 0) {
$("#inbox-streams-container").prepend($(rendered_stream)); $("#inbox-streams-container").prepend($(rendered_stream));
} else { } else {
const previous_stream_key = sorted_stream_keys[stream_index - 1]; const previous_stream_key = sorted_stream_keys[stream_index - 1]!;
$(rendered_stream).insertAfter(get_stream_container(previous_stream_key)); $(rendered_stream).insertAfter(get_stream_container(previous_stream_key));
} }
return !streams_dict.get(stream_key)!.is_hidden; return !streams_dict.get(stream_key)!.is_hidden;
@ -486,7 +486,7 @@ function insert_topics(keys: string[], stream_key: string): void {
} }
if (keys.includes(key)) { if (keys.includes(key)) {
const $previous_row = get_row_from_conversation_key(sorted_keys[i - 1]); const $previous_row = get_row_from_conversation_key(sorted_keys[i - 1]!);
$previous_row.after($(render_inbox_row(stream_topics_data.get(key)))); $previous_row.after($(render_inbox_row(stream_topics_data.get(key))));
} }
} }
@ -1393,7 +1393,7 @@ function move_focus_to_visible_area(): void {
} }
const INBOX_ROW_HEIGHT = 30; const INBOX_ROW_HEIGHT = 30;
const position = $("#inbox-filters")[0].getBoundingClientRect(); const position = $("#inbox-filters")[0]!.getBoundingClientRect();
const inbox_center_x = (position.left + position.right) / 2; const inbox_center_x = (position.left + position.right) / 2;
// We are aiming to get the first row if it is completely visible or the second row. // We are aiming to get the first row if it is completely visible or the second row.
const inbox_row_below_filters = position.bottom + INBOX_ROW_HEIGHT; const inbox_row_below_filters = position.bottom + INBOX_ROW_HEIGHT;

View File

@ -225,10 +225,10 @@ export function create<T>(opts: InputPillCreateOptions<T>): InputPillContainer<T
const idx = store.pills.findIndex((pill) => pill.$element[0] === element); const idx = store.pills.findIndex((pill) => pill.$element[0] === element);
if (idx !== -1) { if (idx !== -1) {
store.pills[idx].$element.remove(); store.pills[idx]!.$element.remove();
const pill = store.pills.splice(idx, 1); const pill = store.pills.splice(idx, 1);
if (store.onPillRemove !== undefined) { if (store.onPillRemove !== undefined) {
store.onPillRemove(pill[0]); store.onPillRemove(pill[0]!);
} }
// This is needed to run the "change" event handler registered in // This is needed to run the "change" event handler registered in
@ -264,7 +264,7 @@ export function create<T>(opts: InputPillCreateOptions<T>): InputPillContainer<T
this.removeLastPill(quiet); this.removeLastPill(quiet);
} }
this.clear(store.$input[0]); this.clear(store.$input[0]!);
}, },
insertManyPills(pills: string | string[]) { insertManyPills(pills: string | string[]) {
@ -285,7 +285,7 @@ export function create<T>(opts: InputPillCreateOptions<T>): InputPillContainer<T
// when using the `text` insertion feature with jQuery the caret is // when using the `text` insertion feature with jQuery the caret is
// placed at the beginning of the input field, so this moves it to // placed at the beginning of the input field, so this moves it to
// the end. // the end.
ui_util.place_caret_at_end(store.$input[0]); ui_util.place_caret_at_end(store.$input[0]!);
// this sends a flag if the operation wasn't completely successful, // this sends a flag if the operation wasn't completely successful,
// which in this case is defined as some of the pills not autofilling // which in this case is defined as some of the pills not autofilling
@ -370,7 +370,7 @@ export function create<T>(opts: InputPillCreateOptions<T>): InputPillContainer<T
// if the pill is successful, it will create the pill and clear // if the pill is successful, it will create the pill and clear
// the input. // the input.
if (funcs.appendPill(store.$input.text().trim())) { if (funcs.appendPill(store.$input.text().trim())) {
funcs.clear(store.$input[0]); funcs.clear(store.$input[0]!);
} }
e.preventDefault(); e.preventDefault();
@ -399,7 +399,7 @@ export function create<T>(opts: InputPillCreateOptions<T>): InputPillContainer<T
break; break;
case "Backspace": { case "Backspace": {
const $next = $pill.next(); const $next = $pill.next();
funcs.removePill($pill[0]); funcs.removePill($pill[0]!);
$next.trigger("focus"); $next.trigger("focus");
// the "Backspace" key in Firefox will go back a page if you do // the "Backspace" key in Firefox will go back a page if you do
// not prevent it. // not prevent it.
@ -439,7 +439,7 @@ export function create<T>(opts: InputPillCreateOptions<T>): InputPillContainer<T
const $pill = $(this).closest(".pill"); const $pill = $(this).closest(".pill");
const $next = $pill.next(); const $next = $pill.next();
funcs.removePill($pill[0]); funcs.removePill($pill[0]!);
$next.trigger("focus"); $next.trigger("focus");
}); });

View File

@ -52,7 +52,9 @@ export function show_generate_integration_url_modal(api_key: string): void {
}, },
}); });
clipboard.on("success", () => { clipboard.on("success", () => {
show_copied_confirmation($("#generate-integration-url-modal .dialog_submit_button")[0]); show_copied_confirmation(
$("#generate-integration-url-modal .dialog_submit_button")[0]!,
);
}); });
$override_topic.on("change", function () { $override_topic.on("change", function () {

View File

@ -206,7 +206,7 @@ function submit_invitation_form(): void {
$("#invite-user-modal .dialog_submit_button").text($t({defaultMessage: "Invite"})); $("#invite-user-modal .dialog_submit_button").text($t({defaultMessage: "Invite"}));
$("#invite-user-modal .dialog_submit_button").prop("disabled", false); $("#invite-user-modal .dialog_submit_button").prop("disabled", false);
$("#invite-user-modal .dialog_exit_button").prop("disabled", false); $("#invite-user-modal .dialog_exit_button").prop("disabled", false);
$invite_status[0].scrollIntoView(); $invite_status[0]!.scrollIntoView();
}, },
}); });
} }
@ -226,7 +226,7 @@ function generate_multiuse_invite(): void {
clipboard.on("success", () => { clipboard.on("success", () => {
const tippy_timeout_in_ms = 800; const tippy_timeout_in_ms = 800;
show_copied_confirmation( show_copied_confirmation(
$("#copy_generated_invite_link")[0], $("#copy_generated_invite_link")[0]!,
() => { () => {
// Do nothing on hide // Do nothing on hide
}, },
@ -243,7 +243,7 @@ function generate_multiuse_invite(): void {
); );
$("#invite-user-modal .dialog_submit_button").prop("disabled", false); $("#invite-user-modal .dialog_submit_button").prop("disabled", false);
$("#invite-user-modal .dialog_exit_button").prop("disabled", false); $("#invite-user-modal .dialog_exit_button").prop("disabled", false);
$invite_status[0].scrollIntoView(); $invite_status[0]!.scrollIntoView();
}, },
}); });
} }
@ -308,7 +308,7 @@ function set_streams_to_join_list_visibility(): void {
const realm_has_default_streams = stream_data.get_default_stream_ids().length !== 0; const realm_has_default_streams = stream_data.get_default_stream_ids().length !== 0;
const hide_streams_list = const hide_streams_list =
realm_has_default_streams && realm_has_default_streams &&
$<HTMLInputElement>("input#invite_select_default_streams")[0].checked; $<HTMLInputElement>("input#invite_select_default_streams")[0]!.checked;
if (hide_streams_list) { if (hide_streams_list) {
$("#streams_to_add .invite-stream-controls").hide(); $("#streams_to_add .invite-stream-controls").hide();
$("#invite-stream-checkboxes").hide(); $("#invite-stream-checkboxes").hide();

View File

@ -114,12 +114,12 @@ export class PanZoomControl {
// See https://github.com/anvaka/panzoom/issues/112 for upstream discussion. // See https://github.com/anvaka/panzoom/issues/112 for upstream discussion.
const {scale, x, y} = e.getTransform(); const {scale, x, y} = e.getTransform();
const image_width = $(".zoom-element > img")[0].clientWidth * scale; const image_width = $(".zoom-element > img")[0]!.clientWidth * scale;
const image_height = $(".zoom-element > img")[0].clientHeight * scale; const image_height = $(".zoom-element > img")[0]!.clientHeight * scale;
const zoom_element_width = $(".zoom-element")[0].clientWidth * scale; const zoom_element_width = $(".zoom-element")[0]!.clientWidth * scale;
const zoom_element_height = $(".zoom-element")[0].clientHeight * scale; const zoom_element_height = $(".zoom-element")[0]!.clientHeight * scale;
const max_translate_x = $(".image-preview")[0].clientWidth; const max_translate_x = $(".image-preview")[0]!.clientWidth;
const max_translate_y = $(".image-preview")[0].clientHeight; const max_translate_y = $(".image-preview")[0]!.clientHeight;
// When the image is dragged out of the image-preview container // When the image is dragged out of the image-preview container
// (max_translate) it will be "snapped" back so that the number // (max_translate) it will be "snapped" back so that the number
@ -377,7 +377,7 @@ export function build_open_media_function(
payload = asset_map.get($preview_src); payload = asset_map.get($preview_src);
} }
if (payload === undefined) { if (payload === undefined) {
payload = parse_media_data($media[0]); payload = parse_media_data($media[0]!);
} }
} }
@ -562,7 +562,7 @@ export function initialize(): void {
// Bind the pan/zoom control the newly created element. // Bind the pan/zoom control the newly created element.
const pan_zoom_control = new PanZoomControl( const pan_zoom_control = new PanZoomControl(
$("#lightbox_overlay .image-preview > .zoom-element")[0], $("#lightbox_overlay .image-preview > .zoom-element")[0]!,
); );
const reset_lightbox_state = function (): void { const reset_lightbox_state = function (): void {

View File

@ -29,7 +29,7 @@ function python_to_js_linkifier(
let current_group = 1; let current_group = 1;
const group_number_to_name: Record<number, string> = {}; const group_number_to_name: Record<number, string> = {};
while (match) { while (match) {
const name = match[1]; const name = match[1]!;
// Replace named group with regular matching group // Replace named group with regular matching group
pattern = pattern.replace("(?P<" + name + ">", "("); pattern = pattern.replace("(?P<" + name + ">", "(");
// Map numbered reference to named reference for template expansion // Map numbered reference to named reference for template expansion
@ -49,7 +49,7 @@ function python_to_js_linkifier(
// JS regexes only support i (case insensitivity) and m (multiline) // JS regexes only support i (case insensitivity) and m (multiline)
// flags, so keep those and ignore the rest // flags, so keep those and ignore the rest
if (match) { if (match) {
const py_flags = match[1]; const py_flags = match[1]!;
for (const flag of py_flags) { for (const flag of py_flags) {
if ("im".includes(flag)) { if ("im".includes(flag)) {

View File

@ -518,10 +518,10 @@ export function create<Key, Item = Key>(
} }
const rendered_row = opts.modifier_html(item, meta.filter_value); const rendered_row = opts.modifier_html(item, meta.filter_value);
if (insert_index === meta.filtered_list.length - 1) { if (insert_index === meta.filtered_list.length - 1) {
const $target_row = opts.html_selector!(meta.filtered_list[insert_index - 1]); const $target_row = opts.html_selector!(meta.filtered_list[insert_index - 1]!);
$target_row.after($(rendered_row)); $target_row.after($(rendered_row));
} else { } else {
const $target_row = opts.html_selector!(meta.filtered_list[insert_index + 1]); const $target_row = opts.html_selector!(meta.filtered_list[insert_index + 1]!);
$target_row.before($(rendered_row)); $target_row.before($(rendered_row));
} }
widget.increase_rendered_offset(); widget.increase_rendered_offset();

View File

@ -250,7 +250,7 @@ function parse_with_options(
misfeature). misfeature).
*/ */
full_name = match[1]; full_name = match[1];
user_id = Number.parseInt(match[2], 10); user_id = Number.parseInt(match[2]!, 10);
if (full_name === undefined) { if (full_name === undefined) {
// For @**|id** syntax // For @**|id** syntax
@ -420,7 +420,7 @@ export function get_topic_links(topic: string): TopicLink[] {
const template_context = Object.fromEntries( const template_context = Object.fromEntries(
match match
.slice(1) .slice(1)
.map((matched_group, i) => [group_number_to_name[i + 1], matched_group]), .map((matched_group, i) => [group_number_to_name[i + 1]!, matched_group]),
); );
const link_url = url_template.expand(template_context); const link_url = url_template.expand(template_context);
// We store the starting index as well, to sort the order of occurrence of the links // We store the starting index as well, to sort the order of occurrence of the links
@ -563,7 +563,7 @@ function handleLinkifier({
assert(item !== undefined); assert(item !== undefined);
const {url_template, group_number_to_name} = item; const {url_template, group_number_to_name} = item;
const template_context = Object.fromEntries( const template_context = Object.fromEntries(
matches.map((match, i) => [group_number_to_name[i + 1], match]), matches.map((match, i) => [group_number_to_name[i + 1]!, match]),
); );
return url_template.expand(template_context); return url_template.expand(template_context);
} }

View File

@ -240,7 +240,7 @@ export function fetch_and_render_message_history(message: Message): void {
.each(function () { .each(function () {
rendered_markdown.update_elements($(this)); rendered_markdown.update_elements($(this));
}); });
const first_element_id = content_edit_history[0].timestamp; const first_element_id = content_edit_history[0]!.timestamp;
messages_overlay_ui.set_initial_element( messages_overlay_ui.set_initial_element(
String(first_element_id), String(first_element_id),
keyboard_handling_context, keyboard_handling_context,

View File

@ -233,7 +233,7 @@ export class MessageListData {
return true; return true;
} }
const recipient_id = Number.parseInt(recipients[0], 10); const recipient_id = Number.parseInt(recipients[0]!, 10);
return ( return (
!muted_users.is_user_muted(recipient_id) && !muted_users.is_user_muted(recipient_id) &&
!muted_users.is_user_muted(message.sender_id) !muted_users.is_user_muted(message.sender_id)
@ -487,7 +487,7 @@ export class MessageListData {
let idx = this.selected_idx() + 1; let idx = this.selected_idx() + 1;
while (idx < this._items.length) { while (idx < this._items.length) {
const msg_id = this._items[idx].id; const msg_id = this._items[idx]!.id;
if (!id_set.has(msg_id)) { if (!id_set.has(msg_id)) {
break; break;
} }

View File

@ -78,7 +78,7 @@ export function message_viewport_info(): MessageViewportInfo {
export function at_rendered_bottom(): boolean { export function at_rendered_bottom(): boolean {
const bottom = scrollTop() + height(); const bottom = scrollTop() + height();
// This also includes bottom whitespace. // This also includes bottom whitespace.
const full_height = $scroll_container[0].scrollHeight; const full_height = $scroll_container[0]!.scrollHeight;
// We only know within a pixel or two if we're // We only know within a pixel or two if we're
// exactly at the bottom, due to browser quirkiness, // exactly at the bottom, due to browser quirkiness,
@ -94,7 +94,7 @@ export function bottom_rendered_message_visible(): boolean {
const $last_row = rows.last_visible(); const $last_row = rows.last_visible();
if ($last_row[0] !== undefined) { if ($last_row[0] !== undefined) {
const message_bottom = $last_row[0].getBoundingClientRect().bottom; const message_bottom = $last_row[0].getBoundingClientRect().bottom;
const bottom_of_feed = $("#compose")[0].getBoundingClientRect().top; const bottom_of_feed = $("#compose")[0]!.getBoundingClientRect().top;
return bottom_of_feed > message_bottom; return bottom_of_feed > message_bottom;
} }
return false; return false;
@ -214,7 +214,7 @@ const top_of_feed = new util.CachedValue({
const bottom_of_feed = new util.CachedValue({ const bottom_of_feed = new util.CachedValue({
compute_value() { compute_value() {
return $("#compose")[0].getBoundingClientRect().top; return $("#compose")[0]!.getBoundingClientRect().top;
}, },
}); });

View File

@ -74,10 +74,10 @@ export function modals_handle_events(event_key: string, context: Context): void
export function set_initial_element(element_id: string, context: Context): void { export function set_initial_element(element_id: string, context: Context): void {
if (element_id) { if (element_id) {
const $current_element = get_element_by_id(element_id, context); const $current_element = get_element_by_id(element_id, context);
const focus_element = $current_element[0].children[0]; const focus_element = $current_element[0]!.children[0];
assert(focus_element instanceof HTMLElement); assert(focus_element instanceof HTMLElement);
activate_element(focus_element, context); activate_element(focus_element, context);
$(`.${CSS.escape(context.items_list_selector)}`)[0].scrollTop = 0; $(`.${CSS.escape(context.items_list_selector)}`)[0]!.scrollTop = 0;
} }
} }
@ -132,7 +132,7 @@ function initialize_focus(event_name: string, context: Context): void {
} }
const $element = get_element_by_id(id, context); const $element = get_element_by_id(id, context);
const focus_element = $element[0].children[0]; const focus_element = $element[0]!.children[0];
assert(focus_element instanceof HTMLElement); assert(focus_element instanceof HTMLElement);
activate_element(focus_element, context); activate_element(focus_element, context);
} }
@ -152,28 +152,28 @@ function scroll_to_element($element: JQuery, context: Context): void {
const $box_item = $(`.${CSS.escape(context.box_item_selector)}`); const $box_item = $(`.${CSS.escape(context.box_item_selector)}`);
// If focused element is first, scroll to the top. // If focused element is first, scroll to the top.
if ($box_item.first()[0].parentElement === $element[0]) { if ($box_item.first()[0]!.parentElement === $element[0]) {
$items_list[0].scrollTop = 0; $items_list[0]!.scrollTop = 0;
} }
// If focused element is last, scroll to the bottom. // If focused element is last, scroll to the bottom.
if ($box_item.last()[0].parentElement === $element[0]) { if ($box_item.last()[0]!.parentElement === $element[0]) {
$items_list[0].scrollTop = $items_list[0].scrollHeight - ($items_list.height() ?? 0); $items_list[0]!.scrollTop = $items_list[0]!.scrollHeight - ($items_list.height() ?? 0);
} }
// If focused element is cut off from the top, scroll up halfway in modal. // If focused element is cut off from the top, scroll up halfway in modal.
if ($element.position().top < 55) { if ($element.position().top < 55) {
// 55 is the minimum distance from the top that will require extra scrolling. // 55 is the minimum distance from the top that will require extra scrolling.
$items_list[0].scrollTop -= $items_list[0].clientHeight / 2; $items_list[0]!.scrollTop -= $items_list[0]!.clientHeight / 2;
} }
// If focused element is cut off from the bottom, scroll down halfway in modal. // If focused element is cut off from the bottom, scroll down halfway in modal.
const dist_from_top = $element.position().top; const dist_from_top = $element.position().top;
const total_dist = dist_from_top + $element[0].clientHeight; const total_dist = dist_from_top + $element[0].clientHeight;
const dist_from_bottom = $items_container[0].clientHeight - total_dist; const dist_from_bottom = $items_container[0]!.clientHeight - total_dist;
if (dist_from_bottom < -4) { if (dist_from_bottom < -4) {
// -4 is the min dist from the bottom that will require extra scrolling. // -4 is the min dist from the bottom that will require extra scrolling.
$items_list[0].scrollTop += $items_list[0].clientHeight / 2; $items_list[0]!.scrollTop += $items_list[0]!.clientHeight / 2;
} }
} }

View File

@ -32,7 +32,7 @@ function retrieve_search_query_data(): SearchData {
const current_filter = narrow_state.filter(); const current_filter = narrow_state.filter();
assert(current_filter !== undefined); assert(current_filter !== undefined);
const search_query = current_filter.operands("search")[0]; const search_query = current_filter.operands("search")[0];
const query_words = search_query.split(" "); const query_words = search_query!.split(" ");
const search_string_result: SearchData = { const search_string_result: SearchData = {
query_words: [], query_words: [],
@ -96,7 +96,7 @@ function pick_empty_narrow_banner(): NarrowBannerData {
return default_banner; return default_banner;
} }
const first_term = current_filter.terms()[0]; const first_term = current_filter.terms()[0]!;
const first_operator = first_term.operator; const first_operator = first_term.operator;
const first_operand = first_term.operand; const first_operand = first_term.operand;
const num_terms = current_filter.terms().length; const num_terms = current_filter.terms().length;

View File

@ -47,7 +47,7 @@ export function compute_narrow_title(filter?: Filter): string {
} }
if (filter.has_operator("dm")) { if (filter.has_operator("dm")) {
const emails = filter.operands("dm")[0]; const emails = filter.operands("dm")[0]!;
const user_ids = people.emails_strings_to_user_ids_string(emails); const user_ids = people.emails_strings_to_user_ids_string(emails);
if (user_ids !== undefined) { if (user_ids !== undefined) {
@ -60,7 +60,7 @@ export function compute_narrow_title(filter?: Filter): string {
} }
if (filter.has_operator("sender")) { if (filter.has_operator("sender")) {
const user = people.get_by_email(filter.operands("sender")[0]); const user = people.get_by_email(filter.operands("sender")[0]!);
if (user) { if (user) {
if (people.is_my_user_id(user.user_id)) { if (people.is_my_user_id(user.user_id)) {
return $t({defaultMessage: "Messages sent by you"}); return $t({defaultMessage: "Messages sent by you"});

View File

@ -737,7 +737,7 @@ export function slug_to_emails(slug: string): string | undefined {
*/ */
const m = /^([\d,]+)(-.*)?/.exec(slug); const m = /^([\d,]+)(-.*)?/.exec(slug);
if (m) { if (m) {
let user_ids_string = m[1]; let user_ids_string = m[1]!;
user_ids_string = exclude_me_from_string(user_ids_string); user_ids_string = exclude_me_from_string(user_ids_string);
return user_ids_string_to_emails_string(user_ids_string); return user_ids_string_to_emails_string(user_ids_string);
} }

View File

@ -126,7 +126,7 @@ function register_click_handlers(): void {
} }
const popover_target = $view_in_playground_button.find( const popover_target = $view_in_playground_button.find(
".playground-links-popover-container", ".playground-links-popover-container",
)[0]; )[0]!;
toggle_playground_links_popover(popover_target, playground_store); toggle_playground_links_popover(popover_target, playground_store);
} }
}, },

View File

@ -46,7 +46,7 @@ export function poll_options_setup(): void {
// setTimeout is needed to here to give time for simplebar to initialise // setTimeout is needed to here to give time for simplebar to initialise
setTimeout(() => { setTimeout(() => {
SortableJS.create($("#add-poll-form .poll-options-list .simplebar-content")[0], { SortableJS.create($("#add-poll-form .poll-options-list .simplebar-content")[0]!, {
onUpdate() { onUpdate() {
// Do nothing on drag; the order is only processed on submission. // Do nothing on drag; the order is only processed on submission.
}, },

View File

@ -192,7 +192,7 @@ export const default_popover_props: Partial<tippy.Props> = {
// $tippy_box[0].hasAttribute("data-reference-hidden"); is the real check // $tippy_box[0].hasAttribute("data-reference-hidden"); is the real check
// but linter wants us to write it like this. // but linter wants us to write it like this.
const is_reference_outside_window = Object.hasOwn( const is_reference_outside_window = Object.hasOwn(
$tippy_box[0].dataset, $tippy_box[0]!.dataset,
"referenceHidden", "referenceHidden",
); );
if (is_reference_outside_window) { if (is_reference_outside_window) {
@ -215,7 +215,7 @@ export const default_popover_props: Partial<tippy.Props> = {
return; return;
} }
const reference_rect = $reference[0].getBoundingClientRect(); const reference_rect = $reference[0]!.getBoundingClientRect();
// This is the logic we want but since it is too expensive to run // This is the logic we want but since it is too expensive to run
// on every scroll, we run a cheaper version of this to just check if // on every scroll, we run a cheaper version of this to just check if
// compose, sticky header or navbar are not obscuring the reference // compose, sticky header or navbar are not obscuring the reference

View File

@ -8,7 +8,7 @@ function get_new_rand(old_random_int: number, max: number): number {
function get_random_item_from_array<T>(array: T[]): T { function get_random_item_from_array<T>(array: T[]): T {
assert(array.length >= 1); assert(array.length >= 1);
return array[Math.floor(Math.random() * array.length)]; return array[Math.floor(Math.random() * array.length)]!;
} }
const current_client_logo_class_names = new Set([ const current_client_logo_class_names = new Set([
@ -40,7 +40,7 @@ function update_client_logo(): void {
current_client_logo_class_names_index, current_client_logo_class_names_index,
client_logos.length, client_logos.length,
); );
const client_logo_elt = client_logos[current_client_logo_class_names_index]; const client_logo_elt = client_logos[current_client_logo_class_names_index]!;
const current_logo_class = client_logo_elt.className; const current_logo_class = client_logo_elt.className;
current_client_logo_class_names.delete(current_logo_class); current_client_logo_class_names.delete(current_logo_class);

View File

@ -58,7 +58,7 @@ export function activate_correct_tab($tabbed_section: JQuery): void {
const $active_list_items = $li.filter(".active"); const $active_list_items = $li.filter(".active");
if (!$active_list_items.length) { if (!$active_list_items.length) {
$li.first().addClass("active"); $li.first().addClass("active");
const tab_key = $li.first()[0].dataset.tabKey; const tab_key = $li.first()[0]!.dataset.tabKey;
if (tab_key) { if (tab_key) {
$blocks.filter("[data-tab-key=" + tab_key + "]").addClass("active"); $blocks.filter("[data-tab-key=" + tab_key + "]").addClass("active");
} else { } else {

View File

@ -89,7 +89,7 @@ export function show_user_list(message_id: number): void {
$("#read_receipts_modal .read_receipts_list").html( $("#read_receipts_modal .read_receipts_list").html(
render_read_receipts(context), render_read_receipts(context),
); );
new SimpleBar($("#read_receipts_modal .modal__content")[0]); new SimpleBar($("#read_receipts_modal .modal__content")[0]!);
} }
}, },
error(xhr) { error(xhr) {

View File

@ -340,7 +340,7 @@ function set_table_focus(row: number, col: number, using_keyboard = false): bool
if (using_keyboard) { if (using_keyboard) {
const scroll_element = $( const scroll_element = $(
"#recent_view_table .table_fix_head .simplebar-content-wrapper", "#recent_view_table .table_fix_head .simplebar-content-wrapper",
)[0]; )[0]!;
const half_height_of_visible_area = scroll_element.offsetHeight / 2; const half_height_of_visible_area = scroll_element.offsetHeight / 2;
const topic_offset = topic_offset_to_visible_area($topic_row); const topic_offset = topic_offset_to_visible_area($topic_row);
@ -1093,14 +1093,14 @@ function topic_offset_to_visible_area($topic_row: JQuery): string | undefined {
} }
const $scroll_container = $("#recent_view_table .table_fix_head"); const $scroll_container = $("#recent_view_table .table_fix_head");
const thead_height = $scroll_container.find("thead").outerHeight(true)!; const thead_height = $scroll_container.find("thead").outerHeight(true)!;
const scroll_container_props = $scroll_container[0].getBoundingClientRect(); const scroll_container_props = $scroll_container[0]!.getBoundingClientRect();
// Since user cannot see row under thead, exclude it as part of the scroll container. // Since user cannot see row under thead, exclude it as part of the scroll container.
const scroll_container_top = scroll_container_props.top + thead_height; const scroll_container_top = scroll_container_props.top + thead_height;
const compose_height = $("#compose").outerHeight(true)!; const compose_height = $("#compose").outerHeight(true)!;
const scroll_container_bottom = scroll_container_props.bottom - compose_height; const scroll_container_bottom = scroll_container_props.bottom - compose_height;
const topic_props = $topic_row[0].getBoundingClientRect(); const topic_props = $topic_row[0]!.getBoundingClientRect();
// Topic is above the visible scroll region. // Topic is above the visible scroll region.
if (topic_props.top < scroll_container_top) { if (topic_props.top < scroll_container_top) {
@ -1119,7 +1119,7 @@ function recenter_focus_if_off_screen(): void {
return; return;
} }
const table_wrapper_element = $("#recent_view_table .table_fix_head")[0]; const table_wrapper_element = $("#recent_view_table .table_fix_head")[0]!;
const $topic_rows = $("#recent_view_table table tbody tr"); const $topic_rows = $("#recent_view_table table tbody tr");
if (row_focus >= $topic_rows.length) { if (row_focus >= $topic_rows.length) {

View File

@ -312,7 +312,7 @@ export const update_elements = ($content: JQuery): void => {
$view_in_playground_button.attr("aria-label", title); $view_in_playground_button.attr("aria-label", title);
} }
const $copy_button = $buttonContainer.find(".copy_codeblock"); const $copy_button = $buttonContainer.find(".copy_codeblock");
const clipboard = new ClipboardJS($copy_button[0], { const clipboard = new ClipboardJS($copy_button[0]!, {
text(copy_element) { text(copy_element) {
const $code = $(copy_element).parent().siblings("code"); const $code = $(copy_element).parent().siblings("code");
return $code.text(); return $code.text();
@ -320,7 +320,7 @@ export const update_elements = ($content: JQuery): void => {
}); });
clipboard.on("success", () => { clipboard.on("success", () => {
show_copied_confirmation($copy_button[0]); show_copied_confirmation($copy_button[0]!);
}); });
$codehilite.addClass("zulip-code-block"); $codehilite.addClass("zulip-code-block");
}); });

View File

@ -5,7 +5,7 @@ import SimpleBar from "simplebar";
type JQueryOrZJQuery = {__zjquery?: true} & JQuery; type JQueryOrZJQuery = {__zjquery?: true} & JQuery;
export function get_content_element($element: JQuery): JQuery { export function get_content_element($element: JQuery): JQuery {
const element = $element.expectOne()[0]; const element = $element.expectOne()[0]!;
const sb = SimpleBar.instances.get(element); const sb = SimpleBar.instances.get(element);
if (sb) { if (sb) {
return $(sb.getContentElement()!); return $(sb.getContentElement()!);
@ -19,7 +19,7 @@ export function get_scroll_element($element: JQueryOrZJQuery): JQuery {
return $element; return $element;
} }
const element = $element.expectOne()[0]; const element = $element.expectOne()[0]!;
const sb = SimpleBar.instances.get(element); const sb = SimpleBar.instances.get(element);
if (sb) { if (sb) {
return $(sb.getScrollElement()!); return $(sb.getScrollElement()!);
@ -32,7 +32,7 @@ export function get_scroll_element($element: JQueryOrZJQuery): JQuery {
} }
export function reset_scrollbar($element: JQuery): void { export function reset_scrollbar($element: JQuery): void {
const element = $element.expectOne()[0]; const element = $element.expectOne()[0]!;
const sb = SimpleBar.instances.get(element); const sb = SimpleBar.instances.get(element);
if (sb) { if (sb) {
sb.getScrollElement()!.scrollTop = 0; sb.getScrollElement()!.scrollTop = 0;

View File

@ -187,7 +187,7 @@ export function extract_property_name($elem: JQuery, for_realm_default_settings?
// "realm_{settings_name}}" because both user and realm default // "realm_{settings_name}}" because both user and realm default
// settings use the same template and each element should have // settings use the same template and each element should have
// unique id. // unique id.
return /^realm_(.*)$/.exec(elem_id.replaceAll("-", "_"))![1]; return /^realm_(.*)$/.exec(elem_id.replaceAll("-", "_"))![1]!;
} }
if (elem_id.startsWith("id_authmethod")) { if (elem_id.startsWith("id_authmethod")) {
@ -197,14 +197,14 @@ export function extract_property_name($elem: JQuery, for_realm_default_settings?
// The [\da-z]+ part of the regexp covers the auth method name itself. // The [\da-z]+ part of the regexp covers the auth method name itself.
// We assume it's not an empty string and can contain only digits and lowercase ASCII letters, // We assume it's not an empty string and can contain only digits and lowercase ASCII letters,
// this is ensured by a respective allowlist-based filter in populate_auth_methods(). // this is ensured by a respective allowlist-based filter in populate_auth_methods().
return /^id_authmethod[\da-z]+_(.*)$/.exec(elem_id)![1]; return /^id_authmethod[\da-z]+_(.*)$/.exec(elem_id)![1]!;
} }
if (elem_id.startsWith("id-custom-profile-field")) { if (elem_id.startsWith("id-custom-profile-field")) {
return /^id_custom_profile_field_(.*)$/.exec(elem_id.replaceAll("-", "_"))![1]; return /^id_custom_profile_field_(.*)$/.exec(elem_id.replaceAll("-", "_"))![1]!;
} }
return /^id_(.*)$/.exec(elem_id.replaceAll("-", "_"))![1]; return /^id_(.*)$/.exec(elem_id.replaceAll("-", "_"))![1]!;
} }
export function get_subsection_property_elements($subsection: JQuery): HTMLElement[] { export function get_subsection_property_elements($subsection: JQuery): HTMLElement[] {
@ -397,7 +397,7 @@ function read_select_field_data_from_form(
} }
} }
$profile_field_form.find("div.choice-row").each(function (this: HTMLElement) { $profile_field_form.find("div.choice-row").each(function (this: HTMLElement) {
const text = $(this).find("input")[0].value; const text = $(this).find("input")[0]!.value;
if (text) { if (text) {
let value = old_option_value_map.get(text); let value = old_option_value_map.get(text);
if (value !== undefined) { if (value !== undefined) {
@ -753,7 +753,7 @@ export function get_auth_method_list_data(): Record<string, boolean> {
for (const method_row of $auth_method_rows) { for (const method_row of $auth_method_rows) {
const method = $(method_row).attr("data-method"); const method = $(method_row).attr("data-method");
assert(method !== undefined); assert(method !== undefined);
new_auth_methods[method] = $(method_row).find<HTMLInputElement>("input")[0].checked; new_auth_methods[method] = $(method_row).find<HTMLInputElement>("input")[0]!.checked;
} }
return new_auth_methods; return new_auth_methods;
@ -957,11 +957,11 @@ export function populate_data_for_request(
$input_elem.attr("id")!, $input_elem.attr("id")!,
); );
assert(match_array !== null); assert(match_array !== null);
property_name = match_array[1]; property_name = match_array[1]!;
} else { } else {
const match_array = /^id_realm_(.*)$/.exec($input_elem.attr("id")!); const match_array = /^id_realm_(.*)$/.exec($input_elem.attr("id")!);
assert(match_array !== null); assert(match_array !== null);
property_name = match_array[1]; property_name = match_array[1]!;
} }
if (property_name === "stream_privacy") { if (property_name === "stream_privacy") {
@ -1146,7 +1146,7 @@ function enable_or_disable_save_button($subsection_elem: JQuery): void {
const $button_wrapper = $subsection_elem.find<tippy.PopperElement>( const $button_wrapper = $subsection_elem.find<tippy.PopperElement>(
".subsection-changes-save", ".subsection-changes-save",
); );
const tippy_instance = $button_wrapper[0]._tippy; const tippy_instance = $button_wrapper[0]!._tippy;
if (disable_save_btn) { if (disable_save_btn) {
// avoid duplication of tippy // avoid duplication of tippy
if (!tippy_instance) { if (!tippy_instance) {
@ -1184,5 +1184,5 @@ export function initialize_disable_btn_hint_popover(
if (hint_text !== undefined) { if (hint_text !== undefined) {
tippy_opts.content = hint_text; tippy_opts.content = hint_text;
} }
tippy.default($btn_wrapper[0], tippy_opts); tippy.default($btn_wrapper[0]!, tippy_opts);
} }

View File

@ -265,7 +265,7 @@ function show_modal(): void {
} }
const formData = new FormData(); const formData = new FormData();
const files = $<HTMLInputElement>("input#emoji_file_input")[0].files; const files = $<HTMLInputElement>("input#emoji_file_input")[0]!.files;
assert(files !== null); assert(files !== null);
for (const [i, file] of [...files].entries()) { for (const [i, file] of [...files].entries()) {
formData.append("file-" + i, file); formData.append("file-" + i, file);

View File

@ -194,7 +194,7 @@ export function populate_linkifiers(linkifiers_data: RealmLinkifiers): void {
}); });
if (current_user.is_admin) { if (current_user.is_admin) {
new SortableJS($linkifiers_table[0], { new SortableJS($linkifiers_table[0]!, {
onUpdate: update_linkifiers_order, onUpdate: update_linkifiers_order,
handle: ".move-handle", handle: ".move-handle",
filter: "input", filter: "input",

View File

@ -421,7 +421,7 @@ function set_up_select_field_edit_form(
// Add blank choice at last // Add blank choice at last
create_choice_row($choice_list); create_choice_row($choice_list);
SortableJS.create($choice_list[0], { SortableJS.create($choice_list[0]!, {
onUpdate() { onUpdate() {
// Do nothing on drag. We process the order on submission // Do nothing on drag. We process the order on submission
}, },
@ -706,7 +706,7 @@ export function do_populate_profile_fields(profile_fields_data: CustomProfileFie
display_in_profile_summary_fields_limit_reached = display_in_profile_summary_fields_count >= 2; display_in_profile_summary_fields_limit_reached = display_in_profile_summary_fields_count >= 2;
if (current_user.is_admin) { if (current_user.is_admin) {
const field_list = $("#admin_profile_fields_table")[0]; const field_list = $("#admin_profile_fields_table")[0]!;
SortableJS.create(field_list, { SortableJS.create(field_list, {
onUpdate: update_field_order, onUpdate: update_field_order,
filter: "input", filter: "input",
@ -724,7 +724,7 @@ function set_up_select_field(): void {
create_choice_row($("#profile_field_choices")); create_choice_row($("#profile_field_choices"));
if (current_user.is_admin) { if (current_user.is_admin) {
const choice_list = $("#profile_field_choices")[0]; const choice_list = $("#profile_field_choices")[0]!;
SortableJS.create(choice_list, { SortableJS.create(choice_list, {
onUpdate() { onUpdate() {
// Do nothing on drag. We process the order on submission // Do nothing on drag. We process the order on submission

View File

@ -114,7 +114,7 @@ export function setup_realm_domains_modal_handlers(): void {
const domain = $widget.find(".new-realm-domain").val(); const domain = $widget.find(".new-realm-domain").val();
const allow_subdomains = $widget.find<HTMLInputElement>( const allow_subdomains = $widget.find<HTMLInputElement>(
"input.new-realm-domain-allow-subdomains", "input.new-realm-domain-allow-subdomains",
)[0].checked; )[0]!.checked;
const data = { const data = {
domain, domain,
allow_subdomains: JSON.stringify(allow_subdomains), allow_subdomains: JSON.stringify(allow_subdomains),

View File

@ -25,7 +25,7 @@ $(() => {
} }
$.fn.get_offset_to_window = function () { $.fn.get_offset_to_window = function () {
return this[0].getBoundingClientRect(); return this[0]!.getBoundingClientRect();
}; };
$.fn.expectOne = function () { $.fn.expectOne = function () {

View File

@ -21,7 +21,7 @@ function expand_spoiler($spoiler: JQuery): void {
// of the content). CSS animations do not work with properties set to // of the content). CSS animations do not work with properties set to
// `auto`, so we get the actual height of the content here and temporarily // `auto`, so we get the actual height of the content here and temporarily
// put it explicitly on the element styling to allow the transition to work. // put it explicitly on the element styling to allow the transition to work.
const spoiler_height = $spoiler[0].scrollHeight; const spoiler_height = $spoiler[0]!.scrollHeight;
$spoiler.height(`${spoiler_height}px`); $spoiler.height(`${spoiler_height}px`);
// The `spoiler-content-open` class has CSS animations defined on it which // The `spoiler-content-open` class has CSS animations defined on it which
// will trigger on the frame after this class change. // will trigger on the frame after this class change.

View File

@ -419,7 +419,7 @@ function populate_messages_sent_over_time(raw_data: unknown): void {
.on("plotly_hover", (data) => { .on("plotly_hover", (data) => {
$("#hoverinfo").show(); $("#hoverinfo").show();
document.querySelector("#hover_date")!.textContent = document.querySelector("#hover_date")!.textContent =
data.points[0].data.text[data.points[0].pointNumber]; data.points[0]!.data.text[data.points[0]!.pointNumber]!;
const values: Plotly.Datum[] = [null, null, null]; const values: Plotly.Datum[] = [null, null, null];
for (const trace of data.points) { for (const trace of data.points) {
values[trace.curveNumber] = trace.y; values[trace.curveNumber] = trace.y;
@ -432,16 +432,16 @@ function populate_messages_sent_over_time(raw_data: unknown): void {
]; ];
for (const [i, value] of values.entries()) { for (const [i, value] of values.entries()) {
if (value !== null) { if (value !== null) {
document.querySelector<HTMLElement>(hover_text_ids[i])!.style.display = document.querySelector<HTMLElement>(hover_text_ids[i]!)!.style.display =
"inline"; "inline";
document.querySelector<HTMLElement>(hover_value_ids[i])!.style.display = document.querySelector<HTMLElement>(hover_value_ids[i]!)!.style.display =
"inline"; "inline";
document.querySelector<HTMLElement>(hover_value_ids[i])!.textContent = document.querySelector<HTMLElement>(hover_value_ids[i]!)!.textContent =
value.toString(); value.toString();
} else { } else {
document.querySelector<HTMLElement>(hover_text_ids[i])!.style.display = document.querySelector<HTMLElement>(hover_text_ids[i]!)!.style.display =
"none"; "none";
document.querySelector<HTMLElement>(hover_value_ids[i])!.style.display = document.querySelector<HTMLElement>(hover_value_ids[i]!)!.style.display =
"none"; "none";
} }
} }
@ -461,13 +461,13 @@ function populate_messages_sent_over_time(raw_data: unknown): void {
let start; let start;
let is_boundary; let is_boundary;
if (aggregation === "day") { if (aggregation === "day") {
start = floor_to_local_day(start_dates[0]); start = floor_to_local_day(start_dates[0]!);
is_boundary = function (date: Date) { is_boundary = function (date: Date) {
return date.getHours() === 0; return date.getHours() === 0;
}; };
} else { } else {
assert(aggregation === "week"); assert(aggregation === "week");
start = floor_to_local_week(start_dates[0]); start = floor_to_local_week(start_dates[0]!);
is_boundary = function (date: Date) { is_boundary = function (date: Date) {
return date.getHours() === 0 && date.getDay() === 0; return date.getHours() === 0 && date.getDay() === 0;
}; };
@ -476,25 +476,25 @@ function populate_messages_sent_over_time(raw_data: unknown): void {
const values: DataByUserType<number[]> = {human: [], bot: [], me: []}; const values: DataByUserType<number[]> = {human: [], bot: [], me: []};
let current: DataByUserType<number> = {human: 0, bot: 0, me: 0}; let current: DataByUserType<number> = {human: 0, bot: 0, me: 0};
let i_init = 0; let i_init = 0;
if (is_boundary(start_dates[0])) { if (is_boundary(start_dates[0]!)) {
current = { current = {
human: data.everyone.human[0], human: data.everyone.human[0]!,
bot: data.everyone.bot[0], bot: data.everyone.bot[0]!,
me: data.user.human[0], me: data.user.human[0]!,
}; };
i_init = 1; i_init = 1;
} }
for (let i = i_init; i < start_dates.length; i += 1) { for (let i = i_init; i < start_dates.length; i += 1) {
if (is_boundary(start_dates[i])) { if (is_boundary(start_dates[i]!)) {
dates.push(start_dates[i]); dates.push(start_dates[i]!);
values.human.push(current.human); values.human.push(current.human);
values.bot.push(current.bot); values.bot.push(current.bot);
values.me.push(current.me); values.me.push(current.me);
current = {human: 0, bot: 0, me: 0}; current = {human: 0, bot: 0, me: 0};
} }
current.human += data.everyone.human[i]; current.human += data.everyone.human[i]!;
current.bot += data.everyone.bot[i]; current.bot += data.everyone.bot[i]!;
current.me += data.user.human[i]; current.me += data.user.human[i]!;
} }
values.human.push(current.human); values.human.push(current.human);
values.bot.push(current.bot); values.bot.push(current.bot);
@ -563,9 +563,9 @@ function populate_messages_sent_over_time(raw_data: unknown): void {
const plotDiv = document.querySelector<Plotly.PlotlyHTMLElement>( const plotDiv = document.querySelector<Plotly.PlotlyHTMLElement>(
"#id_messages_sent_over_time", "#id_messages_sent_over_time",
)!; )!;
assert("visible" in plotDiv.data[0]); assert("visible" in plotDiv.data[0]!);
assert("visible" in plotDiv.data[1]); assert("visible" in plotDiv.data[1]!);
assert("visible" in plotDiv.data[2]); assert("visible" in plotDiv.data[2]!);
traces.me.visible = plotDiv.data[0].visible; traces.me.visible = plotDiv.data[0].visible;
traces.human.visible = plotDiv.data[1].visible; traces.human.visible = plotDiv.data[1].visible;
traces.bot.visible = plotDiv.data[2].visible; traces.bot.visible = plotDiv.data[2].visible;
@ -730,8 +730,8 @@ function populate_messages_sent_by_client(raw_data: unknown): void {
const label_values: {label: string; value: number}[] = []; const label_values: {label: string; value: number}[] = [];
for (let i = 0; i < everyone_month.values.length; i += 1) { for (let i = 0; i < everyone_month.values.length; i += 1) {
label_values.push({ label_values.push({
label: everyone_month.labels[i], label: everyone_month.labels[i]!,
value: everyone_month.labels[i] === "Other" ? -1 : everyone_month.values[i], value: everyone_month.labels[i] === "Other" ? -1 : everyone_month.values[i]!,
}); });
} }
label_values.sort((a, b) => b.value - a.value); label_values.sort((a, b) => b.value - a.value);
@ -754,9 +754,9 @@ function populate_messages_sent_by_client(raw_data: unknown): void {
text: [], text: [],
}; };
for (let i = 0; i < plot_data.values.length; i += 1) { for (let i = 0; i < plot_data.values.length; i += 1) {
if (plot_data.values[i] > 0) { if (plot_data.values[i]! > 0) {
annotations.values.push(plot_data.values[i]); annotations.values.push(plot_data.values[i]!);
annotations.labels.push(plot_data.labels[i]); annotations.labels.push(plot_data.labels[i]!);
annotations.text.push( annotations.text.push(
" " + plot_data.labels[i] + " (" + plot_data.percentages[i] + ")", " " + plot_data.labels[i] + " (" + plot_data.percentages[i] + ")",
); );
@ -1044,7 +1044,7 @@ function populate_number_of_users(raw_data: unknown): void {
.on("plotly_hover", (data) => { .on("plotly_hover", (data) => {
$("#users_hover_info").show(); $("#users_hover_info").show();
document.querySelector("#users_hover_date")!.textContent = document.querySelector("#users_hover_date")!.textContent =
data.points[0].data.text[data.points[0].pointNumber]; data.points[0]!.data.text[data.points[0]!.pointNumber]!;
const values: Plotly.Datum[] = [null, null, null]; const values: Plotly.Datum[] = [null, null, null];
for (const trace of data.points) { for (const trace of data.points) {
values[trace.curveNumber] = trace.y; values[trace.curveNumber] = trace.y;
@ -1056,11 +1056,11 @@ function populate_number_of_users(raw_data: unknown): void {
]; ];
for (const [i, value] of values.entries()) { for (const [i, value] of values.entries()) {
if (value !== null) { if (value !== null) {
document.querySelector<HTMLElement>(hover_value_ids[i])!.style.display = document.querySelector<HTMLElement>(hover_value_ids[i]!)!.style.display =
"inline"; "inline";
document.querySelector(hover_value_ids[i])!.textContent = value.toString(); document.querySelector(hover_value_ids[i]!)!.textContent = value.toString();
} else { } else {
document.querySelector<HTMLElement>(hover_value_ids[i])!.style.display = document.querySelector<HTMLElement>(hover_value_ids[i]!)!.style.display =
"none"; "none";
} }
} }
@ -1185,7 +1185,7 @@ function populate_messages_read_over_time(raw_data: unknown): void {
.on("plotly_hover", (data) => { .on("plotly_hover", (data) => {
$("#read_hover_info").show(); $("#read_hover_info").show();
document.querySelector("#read_hover_date")!.textContent = document.querySelector("#read_hover_date")!.textContent =
data.points[0].data.text[data.points[0].pointNumber]; data.points[0]!.data.text[data.points[0]!.pointNumber]!;
const values: Plotly.Datum[] = [null, null]; const values: Plotly.Datum[] = [null, null];
for (const trace of data.points) { for (const trace of data.points) {
values[trace.curveNumber] = trace.y; values[trace.curveNumber] = trace.y;
@ -1194,18 +1194,20 @@ function populate_messages_read_over_time(raw_data: unknown): void {
const read_hover_value_ids = ["#read_hover_me_value", "#read_hover_everyone_value"]; const read_hover_value_ids = ["#read_hover_me_value", "#read_hover_everyone_value"];
for (const [i, value] of values.entries()) { for (const [i, value] of values.entries()) {
if (value !== null) { if (value !== null) {
document.querySelector<HTMLElement>(read_hover_text_ids[i])!.style.display =
"inline";
document.querySelector<HTMLElement>( document.querySelector<HTMLElement>(
read_hover_value_ids[i], read_hover_text_ids[i]!,
)!.style.display = "inline"; )!.style.display = "inline";
document.querySelector<HTMLElement>(read_hover_value_ids[i])!.textContent = document.querySelector<HTMLElement>(
read_hover_value_ids[i]!,
)!.style.display = "inline";
document.querySelector<HTMLElement>(read_hover_value_ids[i]!)!.textContent =
value.toString(); value.toString();
} else { } else {
document.querySelector<HTMLElement>(read_hover_text_ids[i])!.style.display =
"none";
document.querySelector<HTMLElement>( document.querySelector<HTMLElement>(
read_hover_value_ids[i], read_hover_text_ids[i]!,
)!.style.display = "none";
document.querySelector<HTMLElement>(
read_hover_value_ids[i]!,
)!.style.display = "none"; )!.style.display = "none";
} }
} }
@ -1225,13 +1227,13 @@ function populate_messages_read_over_time(raw_data: unknown): void {
let start; let start;
let is_boundary; let is_boundary;
if (aggregation === "day") { if (aggregation === "day") {
start = floor_to_local_day(start_dates[0]); start = floor_to_local_day(start_dates[0]!);
is_boundary = function (date: Date) { is_boundary = function (date: Date) {
return date.getHours() === 0; return date.getHours() === 0;
}; };
} else { } else {
assert(aggregation === "week"); assert(aggregation === "week");
start = floor_to_local_week(start_dates[0]); start = floor_to_local_week(start_dates[0]!);
is_boundary = function (date: Date) { is_boundary = function (date: Date) {
return date.getHours() === 0 && date.getDay() === 0; return date.getHours() === 0 && date.getDay() === 0;
}; };
@ -1240,19 +1242,19 @@ function populate_messages_read_over_time(raw_data: unknown): void {
const values: DataByEveryoneMe<number[]> = {everyone: [], me: []}; const values: DataByEveryoneMe<number[]> = {everyone: [], me: []};
let current: DataByEveryoneMe<number> = {everyone: 0, me: 0}; let current: DataByEveryoneMe<number> = {everyone: 0, me: 0};
let i_init = 0; let i_init = 0;
if (is_boundary(start_dates[0])) { if (is_boundary(start_dates[0]!)) {
current = {everyone: data.everyone.read[0], me: data.user.read[0]}; current = {everyone: data.everyone.read[0]!, me: data.user.read[0]!};
i_init = 1; i_init = 1;
} }
for (let i = i_init; i < start_dates.length; i += 1) { for (let i = i_init; i < start_dates.length; i += 1) {
if (is_boundary(start_dates[i])) { if (is_boundary(start_dates[i]!)) {
dates.push(start_dates[i]); dates.push(start_dates[i]!);
values.everyone.push(current.everyone); values.everyone.push(current.everyone);
values.me.push(current.me); values.me.push(current.me);
current = {everyone: 0, me: 0}; current = {everyone: 0, me: 0};
} }
current.everyone += data.everyone.read[i]; current.everyone += data.everyone.read[i]!;
current.me += data.user.read[i]; current.me += data.user.read[i]!;
} }
values.everyone.push(current.everyone); values.everyone.push(current.everyone);
values.me.push(current.me); values.me.push(current.me);
@ -1315,8 +1317,8 @@ function populate_messages_read_over_time(raw_data: unknown): void {
const plotDiv = document.querySelector<Plotly.PlotlyHTMLElement>( const plotDiv = document.querySelector<Plotly.PlotlyHTMLElement>(
"#id_messages_read_over_time", "#id_messages_read_over_time",
)!; )!;
assert("visible" in plotDiv.data[0]); assert("visible" in plotDiv.data[0]!);
assert("visible" in plotDiv.data[1]); assert("visible" in plotDiv.data[1]!);
traces.me.visible = plotDiv.data[0].visible; traces.me.visible = plotDiv.data[0].visible;
traces.everyone.visible = plotDiv.data[1].visible; traces.everyone.visible = plotDiv.data[1].visible;
} }

View File

@ -270,7 +270,7 @@ export function slug_to_name(slug: string): string {
*/ */
const m = /^(\d+)(-.*)?$/.exec(slug); const m = /^(\d+)(-.*)?$/.exec(slug);
if (m) { if (m) {
const stream_id = Number.parseInt(m[1], 10); const stream_id = Number.parseInt(m[1]!, 10);
const sub = sub_store.get(stream_id); const sub = sub_store.get(stream_id);
if (sub) { if (sub) {
return sub.name; return sub.name;

View File

@ -285,7 +285,7 @@ export function initialize(): void {
const second_line = $t({defaultMessage: "File name: {filename}"}, {filename}); const second_line = $t({defaultMessage: "File name: {filename}"}, {filename});
$markup.append($("<br>"), $("<span>").text(second_line)); $markup.append($("<br>"), $("<span>").text(second_line));
} }
instance.setContent($markup[0]); instance.setContent($markup[0]!);
return undefined; return undefined;
}, },
onHidden(instance) { onHidden(instance) {

View File

@ -19,19 +19,19 @@ export function next_topic(
const curr_stream_index = streams.indexOf(curr_stream); // -1 if not found const curr_stream_index = streams.indexOf(curr_stream); // -1 if not found
if (curr_stream_index >= 0) { if (curr_stream_index >= 0) {
const stream = streams[curr_stream_index]; const stream = streams[curr_stream_index]!;
const topics = get_topics(stream); const topics = get_topics(stream);
const curr_topic_index = topics.indexOf(curr_topic); // -1 if not found const curr_topic_index = topics.indexOf(curr_topic); // -1 if not found
for (let i = curr_topic_index + 1; i < topics.length; i += 1) { for (let i = curr_topic_index + 1; i < topics.length; i += 1) {
const topic = topics[i]; const topic = topics[i]!;
if (has_unread_messages(stream, topic)) { if (has_unread_messages(stream, topic)) {
return {stream, topic}; return {stream, topic};
} }
} }
for (let i = 0; i < curr_topic_index; i += 1) { for (let i = 0; i < curr_topic_index; i += 1) {
const topic = topics[i]; const topic = topics[i]!;
if (has_unread_messages(stream, topic)) { if (has_unread_messages(stream, topic)) {
return {stream, topic}; return {stream, topic};
} }
@ -39,7 +39,7 @@ export function next_topic(
} }
for (let i = curr_stream_index + 1; i < streams.length; i += 1) { for (let i = curr_stream_index + 1; i < streams.length; i += 1) {
const stream = streams[i]; const stream = streams[i]!;
for (const topic of get_topics(stream)) { for (const topic of get_topics(stream)) {
if (has_unread_messages(stream, topic)) { if (has_unread_messages(stream, topic)) {
return {stream, topic}; return {stream, topic};
@ -48,7 +48,7 @@ export function next_topic(
} }
for (let i = 0; i < curr_stream_index; i += 1) { for (let i = 0; i < curr_stream_index; i += 1) {
const stream = streams[i]; const stream = streams[i]!;
for (const topic of get_topics(stream)) { for (const topic of get_topics(stream)) {
if (has_unread_messages(stream, topic)) { if (has_unread_messages(stream, topic)) {
return {stream, topic}; return {stream, topic};
@ -150,13 +150,13 @@ export function get_next_unread_pm_string(curr_pm: string): string | undefined {
const curr_pm_index = my_pm_strings.indexOf(curr_pm); // -1 if not found const curr_pm_index = my_pm_strings.indexOf(curr_pm); // -1 if not found
for (let i = curr_pm_index + 1; i < my_pm_strings.length; i += 1) { for (let i = curr_pm_index + 1; i < my_pm_strings.length; i += 1) {
if (unread.num_unread_for_user_ids_string(my_pm_strings[i]) > 0) { if (unread.num_unread_for_user_ids_string(my_pm_strings[i]!) > 0) {
return my_pm_strings[i]; return my_pm_strings[i];
} }
} }
for (let i = 0; i < curr_pm_index; i += 1) { for (let i = 0; i < curr_pm_index; i += 1) {
if (unread.num_unread_for_user_ids_string(my_pm_strings[i]) > 0) { if (unread.num_unread_for_user_ids_string(my_pm_strings[i]!) > 0) {
return my_pm_strings[i]; return my_pm_strings[i];
} }
} }

View File

@ -59,7 +59,7 @@ export function highlight_with_escaping_and_regex(regex: RegExp, item: string):
let result = ""; let result = "";
for (const [i, piece] of pieces.entries()) { for (const [i, piece] of pieces.entries()) {
if (regex.test(piece) && (i === 0 || pieces[i - 1].endsWith(" "))) { if (regex.test(piece) && (i === 0 || pieces[i - 1]!.endsWith(" "))) {
// only highlight if the matching part is a word prefix, ie // only highlight if the matching part is a word prefix, ie
// if it is the 1st piece or if there was a space before it // if it is the 1st piece or if there was a space before it
result += "<strong>" + Handlebars.Utils.escapeExpression(piece) + "</strong>"; result += "<strong>" + Handlebars.Utils.escapeExpression(piece) + "</strong>";

View File

@ -72,7 +72,7 @@ export function build_widget(
if (files === null || files === undefined || files.length === 0) { if (files === null || files === undefined || files.length === 0) {
return false; return false;
} }
get_file_input()[0].files = files; get_file_input()[0]!.files = files;
e.preventDefault(); e.preventDefault();
return false; return false;
}); });
@ -160,7 +160,7 @@ export function build_direct_upload_widget(
if (files === null || files === undefined || files.length === 0) { if (files === null || files === undefined || files.length === 0) {
return false; return false;
} }
get_file_input()[0].files = files; get_file_input()[0]!.files = files;
e.preventDefault(); e.preventDefault();
return false; return false;
}); });

View File

@ -35,7 +35,7 @@ export function lower_bound<T1, T2>(
while (len > 0) { while (len > 0) {
step = Math.floor(len / 2); step = Math.floor(len / 2);
middle = first + step; middle = first + step;
if (less(array[middle], value, middle)) { if (less(array[middle]!, value, middle)) {
first = middle; first = middle;
first += 1; first += 1;
len = len - step - 1; len = len - step - 1;
@ -204,7 +204,7 @@ export function find_stream_wildcard_mentions(message_content: string): string |
if (mention === null) { if (mention === null) {
return null; return null;
} }
return mention[2]; return mention[2]!;
} }
export const move_array_elements_to_front = function util_move_array_elements_to_front<T>( export const move_array_elements_to_front = function util_move_array_elements_to_front<T>(

View File

@ -38,7 +38,7 @@ export function eq_array<T>(
return false; return false;
} }
return a.every((item, i) => eq(item, b[i])); return a.every((item, i) => eq(item, b[i]!));
} }
export function ul<T>(opts: Options<T>): Tag<T> { export function ul<T>(opts: Options<T>): Tag<T> {
@ -198,7 +198,7 @@ export function update<T>(
const $child_elems = find().children(); const $child_elems = find().children();
for (const [i, new_node] of new_opts.keyed_nodes.entries()) { for (const [i, new_node] of new_opts.keyed_nodes.entries()) {
const old_node = old_opts.keyed_nodes[i]; const old_node = old_opts.keyed_nodes[i]!;
if (new_node.eq(old_node)) { if (new_node.eq(old_node)) {
continue; continue;
} }