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}
],
"@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",

View File

@ -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: {

View File

@ -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 {

View File

@ -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(() => {

View File

@ -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 {

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
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;
};

View File

@ -5,10 +5,10 @@ import * as scroll_util from "./scroll_util";
type List<Key> = {
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<Key> {
@ -36,7 +36,7 @@ export class ListCursor<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
// here, so we're not so coupled to jQuery, and
// so we instead just get back a widget we can say

View File

@ -56,29 +56,32 @@ type ListWidgetOpts<Key, Item = Key> = {
};
type BaseListWidget = {
clear_event_handlers(): void;
clear_event_handlers: () => void;
};
type ListWidget<Key, Item = Key> = 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<Item>): 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<Item>) => 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 = {

View File

@ -15,20 +15,20 @@ const formDataSchema = z
type FormData = z.infer<typeof formDataSchema>;
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<T = unknown>(
) => void;
migrate: <T = unknown>(
name: string,
v1: number,
v2: number,
callback: (data: unknown) => T,
): T | undefined;
) => T | undefined;
};
const ls = {

View File

@ -33,40 +33,40 @@ import {user_settings} from "./user_settings";
// TODO/typescript: Move this to markdown
type AbstractMap<K, V> = {
keys(): Iterator<K>;
entries(): Iterator<[K, V]>;
get(k: K): V | undefined;
keys: () => Iterator<K>;
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<number, string>}
>;

View File

@ -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 {

View File

@ -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;
}
}

View File

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

View File

@ -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, PrimitiveValue>
>,
): string;
) => string;
};
export function parse(template: string): Template;

View File

@ -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;
};