From 6e220f4dc1e05b2a2f174e6cbe156e13008be83d Mon Sep 17 00:00:00 2001 From: Anders Kaseorg Date: Tue, 26 Dec 2023 16:34:59 -0800 Subject: [PATCH] eslint: Enable @typescript-eslint/method-signature-style. For historical reasons, TypeScript ignores variance errors for method shorthand type declarations even in strict mode. Prefer the correctly checked style. https://typescript-eslint.io/rules/method-signature-style Signed-off-by: Anders Kaseorg --- .eslintrc.json | 1 + web/src/components.ts | 14 +++++------ web/src/compose_fade_users.ts | 6 ++--- web/src/compose_pm_pill.ts | 6 ++++- web/src/electron_bridge.d.ts | 30 ++++++++++++------------ web/src/global.d.ts | 21 ++++++++--------- web/src/list_cursor.ts | 10 ++++---- web/src/list_widget.ts | 43 ++++++++++++++++++---------------- web/src/localstorage.ts | 16 ++++++------- web/src/markdown_config.ts | 38 +++++++++++++++--------------- web/src/messages_overlay_ui.ts | 6 ++--- web/src/poll_widget.ts | 2 +- web/src/upload_widget.ts | 4 ++-- web/src/url-template.d.ts | 4 ++-- web/src/vdom.ts | 2 ++ 15 files changed, 106 insertions(+), 97 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 9e98318d94..355b9a1164 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -182,6 +182,7 @@ {"allowExpressions": true} ], "@typescript-eslint/member-ordering": "error", + "@typescript-eslint/method-signature-style": "error", "@typescript-eslint/no-non-null-assertion": "off", "@typescript-eslint/no-unnecessary-condition": "off", "@typescript-eslint/no-unnecessary-qualifier": "error", diff --git a/web/src/components.ts b/web/src/components.ts index 2badfe522e..f17b4d2295 100644 --- a/web/src/components.ts +++ b/web/src/components.ts @@ -16,13 +16,13 @@ import * as keydown_util from "./keydown_util"; */ export type Toggle = { - maybe_go_left(): boolean; - maybe_go_right(): boolean; - disable_tab(name: string): void; - enable_tab(name: string): void; - value(): string | undefined; - get(): JQuery; - goto(name: string): void; + maybe_go_left: () => boolean; + maybe_go_right: () => boolean; + disable_tab: (name: string) => void; + enable_tab: (name: string) => void; + value: () => string | undefined; + get: () => JQuery; + goto: (name: string) => void; }; export function toggle(opts: { diff --git a/web/src/compose_fade_users.ts b/web/src/compose_fade_users.ts index a77b7935ff..ace9e949c8 100644 --- a/web/src/compose_fade_users.ts +++ b/web/src/compose_fade_users.ts @@ -2,9 +2,9 @@ import * as compose_fade_helper from "./compose_fade_helper"; import * as people from "./people"; export type UserFadeConfig = { - get_user_id($li: JQuery): number; - fade($li: JQuery): void; - unfade($li: JQuery): void; + get_user_id: ($li: JQuery) => number; + fade: ($li: JQuery) => void; + unfade: ($li: JQuery) => void; }; function update_user_row_when_fading($li: JQuery, conf: UserFadeConfig): void { diff --git a/web/src/compose_pm_pill.ts b/web/src/compose_pm_pill.ts index ae6bac363c..918ea09f09 100644 --- a/web/src/compose_pm_pill.ts +++ b/web/src/compose_pm_pill.ts @@ -26,7 +26,11 @@ export function initialize_pill(): UserPillWidget { return pill; } -export function initialize({on_pill_create_or_remove}: {on_pill_create_or_remove(): void}): void { +export function initialize({ + on_pill_create_or_remove, +}: { + on_pill_create_or_remove: () => void; +}): void { widget = initialize_pill(); widget.onPillCreate(() => { diff --git a/web/src/electron_bridge.d.ts b/web/src/electron_bridge.d.ts index 1bdd4a89e6..bf68caeb7a 100644 --- a/web/src/electron_bridge.d.ts +++ b/web/src/electron_bridge.d.ts @@ -6,7 +6,7 @@ export type NotificationData = { tag: string; icon: string; data: unknown; - close(): void; + close: () => void; }; export type ClipboardDecrypter = { @@ -16,25 +16,25 @@ export type ClipboardDecrypter = { }; export type ElectronBridge = { - send_event(eventName: string | symbol, ...args: unknown[]): boolean; - on_event( + send_event: (eventName: string | symbol, ...args: unknown[]) => boolean; + on_event: (( eventName: "logout" | "show-keyboard-shortcuts" | "show-notification-settings", listener: () => void, - ): void; - on_event( - eventName: "send_notification_reply_message", - listener: (message_id: unknown, reply: unknown) => void, - ): void; - new_notification?( + ) => void) & + (( + eventName: "send_notification_reply_message", + listener: (message_id: unknown, reply: unknown) => void, + ) => void); + new_notification?: ( title: string, options: NotificationOptions, dispatch: (type: string, eventInit: EventInit) => boolean, - ): NotificationData; - get_idle_on_system?(): boolean; - get_last_active_on_system?(): number; - get_send_notification_reply_message_supported?(): boolean; - set_send_notification_reply_message_supported?(value: boolean): void; - decrypt_clipboard?(version: number): ClipboardDecrypter; + ) => NotificationData; + get_idle_on_system?: () => boolean; + get_last_active_on_system?: () => number; + get_send_notification_reply_message_supported?: () => boolean; + set_send_notification_reply_message_supported?: (value: boolean) => void; + decrypt_clipboard?: (version: number) => ClipboardDecrypter; }; declare global { diff --git a/web/src/global.d.ts b/web/src/global.d.ts index 177f3b7c1f..d420716160 100644 --- a/web/src/global.d.ts +++ b/web/src/global.d.ts @@ -33,21 +33,20 @@ declare namespace JQueryValidation { // eslint-disable-next-line @typescript-eslint/consistent-type-definitions interface JQuery { - expectOne(): this; - get_offset_to_window(): DOMRect; - tab(action?: string): this; // From web/third/bootstrap + expectOne: () => this; + get_offset_to_window: () => DOMRect; + tab: (action?: string) => this; // From web/third/bootstrap // Types for jquery-caret-plugin - caret(): number; - caret(arg: number | string): this; - range(): JQueryCaretRange; - range(start: number, end?: number): this; - range(text: string): this; - selectAll(): this; - deselectAll(): this; + caret: (() => number) & ((arg: number | string) => this); + range: (() => JQueryCaretRange) & + ((start: number, end?: number) => this) & + ((text: string) => this); + selectAll: () => this; + deselectAll: () => this; // Types for jquery-idle plugin - idle(opts: JQueryIdleOptions): { + idle: (opts: JQueryIdleOptions) => { cancel: () => void; reset: () => void; }; diff --git a/web/src/list_cursor.ts b/web/src/list_cursor.ts index 7cad240b1b..7fb678853b 100644 --- a/web/src/list_cursor.ts +++ b/web/src/list_cursor.ts @@ -5,10 +5,10 @@ import * as scroll_util from "./scroll_util"; type List = { scroll_container_selector: string; - find_li(opts: {key: Key; force_render: boolean}): JQuery; - first_key(): Key | undefined; - prev_key(key: Key): Key | undefined; - next_key(key: Key): Key | undefined; + find_li: (opts: {key: Key; force_render: boolean}) => JQuery; + first_key: () => Key | undefined; + prev_key: (key: Key) => Key | undefined; + next_key: (key: Key) => Key | undefined; }; export class ListCursor { @@ -36,7 +36,7 @@ export class ListCursor { return this.curr_key; } - get_row(key: Key | undefined): {highlight(): void; clear(): void} | undefined { + get_row(key: Key | undefined): {highlight: () => void; clear: () => void} | undefined { // TODO: The list class should probably do more of the work // here, so we're not so coupled to jQuery, and // so we instead just get back a widget we can say diff --git a/web/src/list_widget.ts b/web/src/list_widget.ts index 0001028e76..562375605c 100644 --- a/web/src/list_widget.ts +++ b/web/src/list_widget.ts @@ -56,29 +56,32 @@ type ListWidgetOpts = { }; type BaseListWidget = { - clear_event_handlers(): void; + clear_event_handlers: () => void; }; type ListWidget = BaseListWidget & { - get_current_list(): Item[]; - filter_and_sort(): void; - retain_selected_items(): void; - all_rendered(): boolean; - render(how_many?: number): void; - render_item(item: Item): void; - clear(): void; - set_filter_value(value: string): void; - set_reverse_mode(reverse_mode: boolean): void; - set_sorting_function(sorting_function: string | SortingFunction): void; - set_up_event_handlers(): void; - increase_rendered_offset(): void; - reduce_rendered_offset(): void; - remove_rendered_row(row: JQuery): void; - clean_redraw(): void; - hard_redraw(): void; - insert_rendered_row(item: Item, get_insert_index: (list: Item[], item: Item) => number): void; - sort(sorting_function: string, prop?: string): void; - replace_list_data(list: Key[]): void; + get_current_list: () => Item[]; + filter_and_sort: () => void; + retain_selected_items: () => void; + all_rendered: () => boolean; + render: (how_many?: number) => void; + render_item: (item: Item) => void; + clear: () => void; + set_filter_value: (value: string) => void; + set_reverse_mode: (reverse_mode: boolean) => void; + set_sorting_function: (sorting_function: string | SortingFunction) => void; + set_up_event_handlers: () => void; + increase_rendered_offset: () => void; + reduce_rendered_offset: () => void; + remove_rendered_row: (row: JQuery) => void; + clean_redraw: () => void; + hard_redraw: () => void; + insert_rendered_row: ( + item: Item, + get_insert_index: (list: Item[], item: Item) => number, + ) => void; + sort: (sorting_function: string, prop?: string) => void; + replace_list_data: (list: Key[]) => void; }; const DEFAULTS = { diff --git a/web/src/localstorage.ts b/web/src/localstorage.ts index 4cfacef0c8..d58393fb46 100644 --- a/web/src/localstorage.ts +++ b/web/src/localstorage.ts @@ -15,20 +15,20 @@ const formDataSchema = z type FormData = z.infer; export type LocalStorage = { - setExpiry(expires: number, isGlobal: boolean): LocalStorage; - get(name: string): unknown; - set(name: string, data: unknown): boolean; - remove(name: string): void; - removeDataRegexWithCondition( + setExpiry: (expires: number, isGlobal: boolean) => LocalStorage; + get: (name: string) => unknown; + set: (name: string, data: unknown) => boolean; + remove: (name: string) => void; + removeDataRegexWithCondition: ( name: string, condition_checker: (value: string | null | undefined) => boolean, - ): void; - migrate( + ) => void; + migrate: ( name: string, v1: number, v2: number, callback: (data: unknown) => T, - ): T | undefined; + ) => T | undefined; }; const ls = { diff --git a/web/src/markdown_config.ts b/web/src/markdown_config.ts index 3e49bf9ddc..92bd7ce43e 100644 --- a/web/src/markdown_config.ts +++ b/web/src/markdown_config.ts @@ -33,40 +33,40 @@ import {user_settings} from "./user_settings"; // TODO/typescript: Move this to markdown type AbstractMap = { - keys(): Iterator; - entries(): Iterator<[K, V]>; - get(k: K): V | undefined; + keys: () => Iterator; + entries: () => Iterator<[K, V]>; + get: (k: K) => V | undefined; }; // TODO/typescript: Move this to markdown type MarkdownHelpers = { // user stuff - get_actual_name_from_user_id(user_id: number): string | undefined; - get_user_id_from_name(full_name: string): number | undefined; - is_valid_full_name_and_user_id(full_name: string, user_id: number): boolean; - my_user_id(): number; - is_valid_user_id(user_id: number): boolean; + get_actual_name_from_user_id: (user_id: number) => string | undefined; + get_user_id_from_name: (full_name: string) => number | undefined; + is_valid_full_name_and_user_id: (full_name: string, user_id: number) => boolean; + my_user_id: () => number; + is_valid_user_id: (user_id: number) => boolean; // user groups - get_user_group_from_name(name: string): {id: number; name: string} | undefined; - is_member_of_user_group(user_id: number, user_group_id: number): boolean; + get_user_group_from_name: (name: string) => {id: number; name: string} | undefined; + is_member_of_user_group: (user_id: number, user_group_id: number) => boolean; // stream hashes - get_stream_by_name(stream_name: string): {stream_id: number; name: string} | undefined; - stream_hash(stream_id: number): string; - stream_topic_hash(stream_id: number, topic: string): string; + get_stream_by_name: (stream_name: string) => {stream_id: number; name: string} | undefined; + stream_hash: (stream_id: number) => string; + stream_topic_hash: (stream_id: number, topic: string) => string; // settings - should_translate_emoticons(): boolean; + should_translate_emoticons: () => boolean; // emojis - get_emoji_name(codepoint: string): string | undefined; - get_emoji_codepoint(emoji_name: string): string | undefined; - get_emoticon_translations(): {regex: RegExp; replacement_text: string}[]; - get_realm_emoji_url(emoji_name: string): string | undefined; + get_emoji_name: (codepoint: string) => string | undefined; + get_emoji_codepoint: (emoji_name: string) => string | undefined; + get_emoticon_translations: () => {regex: RegExp; replacement_text: string}[]; + get_realm_emoji_url: (emoji_name: string) => string | undefined; // linkifiers - get_linkifier_map(): AbstractMap< + get_linkifier_map: () => AbstractMap< RegExp, {url_template: url_template_lib.Template; group_number_to_name: Record} >; diff --git a/web/src/messages_overlay_ui.ts b/web/src/messages_overlay_ui.ts index d5cea7d22c..3f65986a26 100644 --- a/web/src/messages_overlay_ui.ts +++ b/web/src/messages_overlay_ui.ts @@ -7,9 +7,9 @@ type Context = { row_item_selector: string; box_item_selector: string; id_attribute_name: string; - get_items_ids(): number[]; - on_enter(): void; - on_delete(): void; + get_items_ids: () => number[]; + on_enter: () => void; + on_delete: () => void; }; export function row_with_focus(context: Context): JQuery { diff --git a/web/src/poll_widget.ts b/web/src/poll_widget.ts index 6ec0f0133a..940f9959ff 100644 --- a/web/src/poll_widget.ts +++ b/web/src/poll_widget.ts @@ -28,7 +28,7 @@ type ExtraData = declare global { // eslint-disable-next-line @typescript-eslint/consistent-type-definitions interface JQuery { - handle_events(events: Event[]): void; + handle_events: (events: Event[]) => void; } } diff --git a/web/src/upload_widget.ts b/web/src/upload_widget.ts index 2de5f311a1..94406741dc 100644 --- a/web/src/upload_widget.ts +++ b/web/src/upload_widget.ts @@ -1,8 +1,8 @@ import {$t} from "./i18n"; export type UploadWidget = { - clear(): void; - close(): void; + clear: () => void; + close: () => void; }; export type UploadFunction = ( diff --git a/web/src/url-template.d.ts b/web/src/url-template.d.ts index dff60bf82f..02b0db4f53 100644 --- a/web/src/url-template.d.ts +++ b/web/src/url-template.d.ts @@ -7,12 +7,12 @@ declare module "url-template" { export type PrimitiveValue = string | number | boolean | null; export type Template = { - expand( + expand: ( context: Record< string, PrimitiveValue | PrimitiveValue[] | Record >, - ): string; + ) => string; }; export function parse(template: string): Template; diff --git a/web/src/vdom.ts b/web/src/vdom.ts index 160e188593..37d2e727c1 100644 --- a/web/src/vdom.ts +++ b/web/src/vdom.ts @@ -5,6 +5,8 @@ import * as blueslip from "./blueslip"; export type Node = { key: unknown; render: () => string; + // TODO: This is hiding type errors due to bivariance. + // eslint-disable-next-line @typescript-eslint/method-signature-style eq(other: Node): boolean; };