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 <anders@zulip.com>
This commit is contained in:
Anders Kaseorg 2023-12-26 16:34:59 -08:00 committed by Anders Kaseorg
parent b44daf080c
commit 6e220f4dc1
15 changed files with 106 additions and 97 deletions

View File

@ -182,6 +182,7 @@
{"allowExpressions": true} {"allowExpressions": true}
], ],
"@typescript-eslint/member-ordering": "error", "@typescript-eslint/member-ordering": "error",
"@typescript-eslint/method-signature-style": "error",
"@typescript-eslint/no-non-null-assertion": "off", "@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/no-unnecessary-condition": "off", "@typescript-eslint/no-unnecessary-condition": "off",
"@typescript-eslint/no-unnecessary-qualifier": "error", "@typescript-eslint/no-unnecessary-qualifier": "error",

View File

@ -16,13 +16,13 @@ import * as keydown_util from "./keydown_util";
*/ */
export type Toggle = { export type Toggle = {
maybe_go_left(): boolean; maybe_go_left: () => boolean;
maybe_go_right(): boolean; maybe_go_right: () => boolean;
disable_tab(name: string): void; disable_tab: (name: string) => void;
enable_tab(name: string): void; enable_tab: (name: string) => void;
value(): string | undefined; value: () => string | undefined;
get(): JQuery; get: () => JQuery;
goto(name: string): void; goto: (name: string) => void;
}; };
export function toggle(opts: { export function toggle(opts: {

View File

@ -2,9 +2,9 @@ import * as compose_fade_helper from "./compose_fade_helper";
import * as people from "./people"; import * as people from "./people";
export type UserFadeConfig = { export type UserFadeConfig = {
get_user_id($li: JQuery): number; get_user_id: ($li: JQuery) => number;
fade($li: JQuery): void; fade: ($li: JQuery) => void;
unfade($li: JQuery): void; unfade: ($li: JQuery) => void;
}; };
function update_user_row_when_fading($li: JQuery, conf: UserFadeConfig): void { function update_user_row_when_fading($li: JQuery, conf: UserFadeConfig): void {

View File

@ -26,7 +26,11 @@ export function initialize_pill(): UserPillWidget {
return pill; 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 = initialize_pill();
widget.onPillCreate(() => { widget.onPillCreate(() => {

View File

@ -6,7 +6,7 @@ export type NotificationData = {
tag: string; tag: string;
icon: string; icon: string;
data: unknown; data: unknown;
close(): void; close: () => void;
}; };
export type ClipboardDecrypter = { export type ClipboardDecrypter = {
@ -16,25 +16,25 @@ export type ClipboardDecrypter = {
}; };
export type ElectronBridge = { export type ElectronBridge = {
send_event(eventName: string | symbol, ...args: unknown[]): boolean; send_event: (eventName: string | symbol, ...args: unknown[]) => boolean;
on_event( on_event: ((
eventName: "logout" | "show-keyboard-shortcuts" | "show-notification-settings", eventName: "logout" | "show-keyboard-shortcuts" | "show-notification-settings",
listener: () => void, listener: () => void,
): void; ) => void) &
on_event( ((
eventName: "send_notification_reply_message", eventName: "send_notification_reply_message",
listener: (message_id: unknown, reply: unknown) => void, listener: (message_id: unknown, reply: unknown) => void,
): void; ) => void);
new_notification?( new_notification?: (
title: string, title: string,
options: NotificationOptions, options: NotificationOptions,
dispatch: (type: string, eventInit: EventInit) => boolean, dispatch: (type: string, eventInit: EventInit) => boolean,
): NotificationData; ) => NotificationData;
get_idle_on_system?(): boolean; get_idle_on_system?: () => boolean;
get_last_active_on_system?(): number; get_last_active_on_system?: () => number;
get_send_notification_reply_message_supported?(): boolean; get_send_notification_reply_message_supported?: () => boolean;
set_send_notification_reply_message_supported?(value: boolean): void; set_send_notification_reply_message_supported?: (value: boolean) => void;
decrypt_clipboard?(version: number): ClipboardDecrypter; decrypt_clipboard?: (version: number) => ClipboardDecrypter;
}; };
declare global { declare global {

21
web/src/global.d.ts vendored
View File

@ -33,21 +33,20 @@ declare namespace JQueryValidation {
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions // eslint-disable-next-line @typescript-eslint/consistent-type-definitions
interface JQuery { interface JQuery {
expectOne(): this; expectOne: () => this;
get_offset_to_window(): DOMRect; get_offset_to_window: () => DOMRect;
tab(action?: string): this; // From web/third/bootstrap tab: (action?: string) => this; // From web/third/bootstrap
// Types for jquery-caret-plugin // Types for jquery-caret-plugin
caret(): number; caret: (() => number) & ((arg: number | string) => this);
caret(arg: number | string): this; range: (() => JQueryCaretRange) &
range(): JQueryCaretRange; ((start: number, end?: number) => this) &
range(start: number, end?: number): this; ((text: string) => this);
range(text: string): this; selectAll: () => this;
selectAll(): this; deselectAll: () => this;
deselectAll(): this;
// Types for jquery-idle plugin // Types for jquery-idle plugin
idle(opts: JQueryIdleOptions): { idle: (opts: JQueryIdleOptions) => {
cancel: () => void; cancel: () => void;
reset: () => void; reset: () => void;
}; };

View File

@ -5,10 +5,10 @@ import * as scroll_util from "./scroll_util";
type List<Key> = { type List<Key> = {
scroll_container_selector: string; scroll_container_selector: string;
find_li(opts: {key: Key; force_render: boolean}): JQuery; find_li: (opts: {key: Key; force_render: boolean}) => JQuery;
first_key(): Key | undefined; first_key: () => Key | undefined;
prev_key(key: Key): Key | undefined; prev_key: (key: Key) => Key | undefined;
next_key(key: Key): Key | undefined; next_key: (key: Key) => Key | undefined;
}; };
export class ListCursor<Key> { export class ListCursor<Key> {
@ -36,7 +36,7 @@ export class ListCursor<Key> {
return this.curr_key; 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 // TODO: The list class should probably do more of the work
// here, so we're not so coupled to jQuery, and // here, so we're not so coupled to jQuery, and
// so we instead just get back a widget we can say // so we instead just get back a widget we can say

View File

@ -56,29 +56,32 @@ type ListWidgetOpts<Key, Item = Key> = {
}; };
type BaseListWidget = { type BaseListWidget = {
clear_event_handlers(): void; clear_event_handlers: () => void;
}; };
type ListWidget<Key, Item = Key> = BaseListWidget & { type ListWidget<Key, Item = Key> = BaseListWidget & {
get_current_list(): Item[]; get_current_list: () => Item[];
filter_and_sort(): void; filter_and_sort: () => void;
retain_selected_items(): void; retain_selected_items: () => void;
all_rendered(): boolean; all_rendered: () => boolean;
render(how_many?: number): void; render: (how_many?: number) => void;
render_item(item: Item): void; render_item: (item: Item) => void;
clear(): void; clear: () => void;
set_filter_value(value: string): void; set_filter_value: (value: string) => void;
set_reverse_mode(reverse_mode: boolean): void; set_reverse_mode: (reverse_mode: boolean) => void;
set_sorting_function(sorting_function: string | SortingFunction<Item>): void; set_sorting_function: (sorting_function: string | SortingFunction<Item>) => void;
set_up_event_handlers(): void; set_up_event_handlers: () => void;
increase_rendered_offset(): void; increase_rendered_offset: () => void;
reduce_rendered_offset(): void; reduce_rendered_offset: () => void;
remove_rendered_row(row: JQuery): void; remove_rendered_row: (row: JQuery) => void;
clean_redraw(): void; clean_redraw: () => void;
hard_redraw(): void; hard_redraw: () => void;
insert_rendered_row(item: Item, get_insert_index: (list: Item[], item: Item) => number): void; insert_rendered_row: (
sort(sorting_function: string, prop?: string): void; item: Item,
replace_list_data(list: Key[]): void; get_insert_index: (list: Item[], item: Item) => number,
) => void;
sort: (sorting_function: string, prop?: string) => void;
replace_list_data: (list: Key[]) => void;
}; };
const DEFAULTS = { const DEFAULTS = {

View File

@ -15,20 +15,20 @@ const formDataSchema = z
type FormData = z.infer<typeof formDataSchema>; type FormData = z.infer<typeof formDataSchema>;
export type LocalStorage = { export type LocalStorage = {
setExpiry(expires: number, isGlobal: boolean): LocalStorage; setExpiry: (expires: number, isGlobal: boolean) => LocalStorage;
get(name: string): unknown; get: (name: string) => unknown;
set(name: string, data: unknown): boolean; set: (name: string, data: unknown) => boolean;
remove(name: string): void; remove: (name: string) => void;
removeDataRegexWithCondition( removeDataRegexWithCondition: (
name: string, name: string,
condition_checker: (value: string | null | undefined) => boolean, condition_checker: (value: string | null | undefined) => boolean,
): void; ) => void;
migrate<T = unknown>( migrate: <T = unknown>(
name: string, name: string,
v1: number, v1: number,
v2: number, v2: number,
callback: (data: unknown) => T, callback: (data: unknown) => T,
): T | undefined; ) => T | undefined;
}; };
const ls = { const ls = {

View File

@ -33,40 +33,40 @@ import {user_settings} from "./user_settings";
// TODO/typescript: Move this to markdown // TODO/typescript: Move this to markdown
type AbstractMap<K, V> = { type AbstractMap<K, V> = {
keys(): Iterator<K>; keys: () => Iterator<K>;
entries(): Iterator<[K, V]>; entries: () => Iterator<[K, V]>;
get(k: K): V | undefined; get: (k: K) => V | undefined;
}; };
// TODO/typescript: Move this to markdown // TODO/typescript: Move this to markdown
type MarkdownHelpers = { type MarkdownHelpers = {
// user stuff // user stuff
get_actual_name_from_user_id(user_id: number): string | undefined; get_actual_name_from_user_id: (user_id: number) => string | undefined;
get_user_id_from_name(full_name: string): number | 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; is_valid_full_name_and_user_id: (full_name: string, user_id: number) => boolean;
my_user_id(): number; my_user_id: () => number;
is_valid_user_id(user_id: number): boolean; is_valid_user_id: (user_id: number) => boolean;
// user groups // user groups
get_user_group_from_name(name: string): {id: number; name: string} | undefined; 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; is_member_of_user_group: (user_id: number, user_group_id: number) => boolean;
// stream hashes // stream hashes
get_stream_by_name(stream_name: string): {stream_id: number; name: string} | undefined; get_stream_by_name: (stream_name: string) => {stream_id: number; name: string} | undefined;
stream_hash(stream_id: number): string; stream_hash: (stream_id: number) => string;
stream_topic_hash(stream_id: number, topic: string): string; stream_topic_hash: (stream_id: number, topic: string) => string;
// settings // settings
should_translate_emoticons(): boolean; should_translate_emoticons: () => boolean;
// emojis // emojis
get_emoji_name(codepoint: string): string | undefined; get_emoji_name: (codepoint: string) => string | undefined;
get_emoji_codepoint(emoji_name: string): string | undefined; get_emoji_codepoint: (emoji_name: string) => string | undefined;
get_emoticon_translations(): {regex: RegExp; replacement_text: string}[]; get_emoticon_translations: () => {regex: RegExp; replacement_text: string}[];
get_realm_emoji_url(emoji_name: string): string | undefined; get_realm_emoji_url: (emoji_name: string) => string | undefined;
// linkifiers // linkifiers
get_linkifier_map(): AbstractMap< get_linkifier_map: () => AbstractMap<
RegExp, RegExp,
{url_template: url_template_lib.Template; group_number_to_name: Record<number, string>} {url_template: url_template_lib.Template; group_number_to_name: Record<number, string>}
>; >;

View File

@ -7,9 +7,9 @@ type Context = {
row_item_selector: string; row_item_selector: string;
box_item_selector: string; box_item_selector: string;
id_attribute_name: string; id_attribute_name: string;
get_items_ids(): number[]; get_items_ids: () => number[];
on_enter(): void; on_enter: () => void;
on_delete(): void; on_delete: () => void;
}; };
export function row_with_focus(context: Context): JQuery { export function row_with_focus(context: Context): JQuery {

View File

@ -28,7 +28,7 @@ type ExtraData =
declare global { declare global {
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions // eslint-disable-next-line @typescript-eslint/consistent-type-definitions
interface JQuery { interface JQuery {
handle_events(events: Event[]): void; handle_events: (events: Event[]) => void;
} }
} }

View File

@ -1,8 +1,8 @@
import {$t} from "./i18n"; import {$t} from "./i18n";
export type UploadWidget = { export type UploadWidget = {
clear(): void; clear: () => void;
close(): void; close: () => void;
}; };
export type UploadFunction = ( export type UploadFunction = (

View File

@ -7,12 +7,12 @@ declare module "url-template" {
export type PrimitiveValue = string | number | boolean | null; export type PrimitiveValue = string | number | boolean | null;
export type Template = { export type Template = {
expand( expand: (
context: Record< context: Record<
string, string,
PrimitiveValue | PrimitiveValue[] | Record<string, PrimitiveValue> PrimitiveValue | PrimitiveValue[] | Record<string, PrimitiveValue>
>, >,
): string; ) => string;
}; };
export function parse(template: string): Template; export function parse(template: string): Template;

View File

@ -5,6 +5,8 @@ import * as blueslip from "./blueslip";
export type Node = { export type Node = {
key: unknown; key: unknown;
render: () => string; render: () => string;
// TODO: This is hiding type errors due to bivariance.
// eslint-disable-next-line @typescript-eslint/method-signature-style
eq(other: Node): boolean; eq(other: Node): boolean;
}; };