From 55c2e9b512b8a40e8709a901b11d3709ef4ed61f Mon Sep 17 00:00:00 2001 From: Benedikt Werner <1benediktwerner@gmail.com> Date: Thu, 15 Jul 2021 16:11:31 +0200 Subject: [PATCH] noImplicitAny for ui/site --- ui/@types/lichess/index.d.ts | 5 +++++ ui/site/src/captcha.ts | 5 ++++- ui/site/src/clas.ts | 8 ++++--- ui/site/src/component/chat.ts | 4 ++-- ui/site/src/component/friends.ts | 4 +++- ui/site/src/component/module-launchers.ts | 4 ++-- ui/site/src/component/pubsub.ts | 16 +++++++------- ui/site/src/component/reload.ts | 19 +++++++++++------ ui/site/src/component/serviceWorker.ts | 4 ++-- ui/site/src/component/top-bar.ts | 4 ++-- ui/site/src/component/watchers.ts | 7 ++++-- ui/site/src/component/widget.ts | 4 ++-- ui/site/src/coordinate.ts | 26 +++++++++++------------ ui/site/src/forum.ts | 4 ++-- ui/site/src/gameSearch.ts | 4 ++-- ui/site/src/modActivity.ts | 2 +- ui/site/src/teamBattleForm.ts | 4 ++-- ui/site/src/userComplete.ts | 14 ++++++------ ui/site/tsconfig.json | 1 - ui/site/types/tablesort.d.ts | 1 + 20 files changed, 80 insertions(+), 60 deletions(-) create mode 100644 ui/site/types/tablesort.d.ts diff --git a/ui/@types/lichess/index.d.ts b/ui/@types/lichess/index.d.ts index b8ddb5a8f1..55b64d25ff 100644 --- a/ui/@types/lichess/index.d.ts +++ b/ui/@types/lichess/index.d.ts @@ -255,6 +255,7 @@ interface Window { palantir?: { palantir(opts: PalantirOpts): Palantir; }; + LichessChat(element: Element, opts: any): unknown; [key: string]: any; // TODO } @@ -275,6 +276,10 @@ interface LightUser extends LightUserNoId { id: string; } +interface LightUserOnline extends LightUser { + online: boolean; +} + interface Navigator { deviceMemory?: number; // https://developer.mozilla.org/en-US/docs/Web/API/Navigator/deviceMemory } diff --git a/ui/site/src/captcha.ts b/ui/site/src/captcha.ts index 3c6c51aa90..194a0ee87f 100644 --- a/ui/site/src/captcha.ts +++ b/ui/site/src/captcha.ts @@ -12,7 +12,10 @@ function init() { $input = $captcha.find('input').val(''), cg = domData.get($board[0]!, 'chessground'); - if (!cg) return (failed = true); + if (!cg) { + failed = true; + return; + } const fen = cg.getFen(), destsObj = $board.data('moves'), diff --git a/ui/site/src/clas.ts b/ui/site/src/clas.ts index 48a06e2d56..5ca0aa8477 100644 --- a/ui/site/src/clas.ts +++ b/ui/site/src/clas.ts @@ -4,6 +4,8 @@ import { loadScript } from './component/assets'; import extendTablesortNumber from './component/tablesort-number'; import * as xhr from 'common/xhr'; +import type { Result as UserCompleteResult } from './userComplete'; + lichess.load.then(() => { $('table.sortable').each(function (this: HTMLElement) { tablesort(this, { @@ -47,14 +49,14 @@ lichess.load.then(() => { }) ) .then( - res => { + (res: UserCompleteResult) => { const current = currentUserIds(); callback(res.result.filter(t => !current.includes(t.id))); }, _ => callback([]) ); }, - template: o => + template: (o: LightUserOnline) => '' + o.title + ' ' : '') + o.name + '', - replace: o => '$1' + o.name + '\n', + replace: (o: LightUserOnline) => '$1' + o.name + '\n', }, ]); diff --git a/ui/site/src/component/chat.ts b/ui/site/src/component/chat.ts index ae2141203e..ca4bdcd0f1 100644 --- a/ui/site/src/component/chat.ts +++ b/ui/site/src/component/chat.ts @@ -1,10 +1,10 @@ import { loadCssPath } from './assets'; -const chat = data => +const chat = (data: any) => new Promise(resolve => requestAnimationFrame(() => { data.loadCss = loadCssPath; - resolve(window.LichessChat(document.querySelector('.mchat'), data)); + resolve(window.LichessChat(document.querySelector('.mchat')!, data)); }) ); diff --git a/ui/site/src/component/friends.ts b/ui/site/src/component/friends.ts index ce3cd6c915..5b62f6cec0 100644 --- a/ui/site/src/component/friends.ts +++ b/ui/site/src/component/friends.ts @@ -30,7 +30,9 @@ export default class OnlineFriends { this.trans = trans(JSON.parse(this.el.getAttribute('data-i18n')!)); this.users = new Map(); pubsub.on('socket.in.following_onlines', this.receive); - ['enters', 'leaves', 'playing', 'stopped_playing'].forEach(k => pubsub.on('socket.in.following_' + k, this[k])); + (['enters', 'leaves', 'playing', 'stopped_playing'] as const).forEach(k => + pubsub.on('socket.in.following_' + k, this[k]) + ); } receive = (friends: TitleName[], msg: { playing: string[]; patrons: string[] }) => { this.users.clear(); diff --git a/ui/site/src/component/module-launchers.ts b/ui/site/src/component/module-launchers.ts index a54e7325d4..29230814a8 100644 --- a/ui/site/src/component/module-launchers.ts +++ b/ui/site/src/component/module-launchers.ts @@ -7,12 +7,12 @@ export default function moduleLaunchers() { else if (li.study || li.practice || li.relay) startAnalyse(li.study || li.practice || li.relay); } -function startUserAnalysis(cfg) { +function startUserAnalysis(cfg: any) { cfg.$side = $('.analyse__side').clone(); startAnalyse(cfg); } -function startAnalyse(cfg) { +function startAnalyse(cfg: any) { lichess.socket = new StrongSocket(cfg.socketUrl || '/analysis/socket/v5', cfg.socketVersion, { receive: (t: string, d: any) => analyse.socketReceive(t, d), }); diff --git a/ui/site/src/component/pubsub.ts b/ui/site/src/component/pubsub.ts index a44d7afdcb..99ba61c274 100644 --- a/ui/site/src/component/pubsub.ts +++ b/ui/site/src/component/pubsub.ts @@ -1,21 +1,21 @@ -const subs: Array<() => void> = []; +const subs: Dictionary<(() => void)[]> = Object.create(null); const pubsub: Pubsub = { on(name: string, cb) { - subs[name] = subs[name] || []; - subs[name].push(cb); + (subs[name] = subs[name] || []).push(cb); }, off(name: string, cb) { - if (subs[name]) - for (const i in subs[name]) { - if (subs[name][i] === cb) { - subs[name].splice(i); + const cbs = subs[name]; + if (cbs) + for (const i in cbs) { + if (cbs[i] === cb) { + cbs.splice(+i); break; } } }, emit(name: string, ...args: any[]) { - if (subs[name]) for (const i in subs[name]) subs[name][i].apply(null, args); + for (const fn of subs[name] || []) fn.apply(null, args); }, }; diff --git a/ui/site/src/component/reload.ts b/ui/site/src/component/reload.ts index b733f6d3af..712e576f9f 100644 --- a/ui/site/src/component/reload.ts +++ b/ui/site/src/component/reload.ts @@ -1,15 +1,20 @@ let redirectInProgress: false | string = false; -export const redirect = obj => { - let url; - if (typeof obj == 'string') url = obj; +interface Opts { + url: string; + cookie: Cookie; +} + +export const redirect = (opts: string | Opts) => { + let url: string; + if (typeof opts == 'string') url = opts; else { - url = obj.url; - if (obj.cookie) { + url = opts.url; + if (opts.cookie) { const domain = document.domain.replace(/^.+(\.[^.]+\.[^.]+)$/, '$1'); const cookie = [ - encodeURIComponent(obj.cookie.name) + '=' + obj.cookie.value, - '; max-age=' + obj.cookie.maxAge, + encodeURIComponent(opts.cookie.name) + '=' + opts.cookie.value, + '; max-age=' + opts.cookie.maxAge, '; path=/', '; domain=' + domain, ].join(''); diff --git a/ui/site/src/component/serviceWorker.ts b/ui/site/src/component/serviceWorker.ts index 9d8111c78f..485745e761 100644 --- a/ui/site/src/component/serviceWorker.ts +++ b/ui/site/src/component/serviceWorker.ts @@ -21,11 +21,11 @@ export default function () { const store = storage.make('push-subscribed'); const vapid = document.body.getAttribute('data-vapid'); if (vapid && Notification.permission == 'granted') - return reg.pushManager.getSubscription().then(sub => { + reg.pushManager.getSubscription().then(sub => { const resub = parseInt(store.get() || '0', 10) + 43200000 < Date.now(); // 12 hours const applicationServerKey = Uint8Array.from(atob(vapid), c => c.charCodeAt(0)); if (!sub || resub) { - return reg.pushManager + reg.pushManager .subscribe({ userVisibleOnly: true, applicationServerKey: applicationServerKey, diff --git a/ui/site/src/component/top-bar.ts b/ui/site/src/component/top-bar.ts index addf377639..a9a1087700 100644 --- a/ui/site/src/component/top-bar.ts +++ b/ui/site/src/component/top-bar.ts @@ -36,7 +36,7 @@ export default function () { { // challengeApp - let instance, booted: boolean; + let instance: any, booted: boolean; const $toggle = $('#challenge-toggle'); $toggle.one('mouseover click', () => load()); const load = function (data?: any) { @@ -69,7 +69,7 @@ export default function () { { // notifyApp - let instance, booted: boolean; + let instance: any, booted: boolean; const $toggle = $('#notify-toggle'), selector = '#notify-app'; diff --git a/ui/site/src/component/watchers.ts b/ui/site/src/component/watchers.ts index 07d5b51680..37e8ac5e4d 100644 --- a/ui/site/src/component/watchers.ts +++ b/ui/site/src/component/watchers.ts @@ -21,10 +21,13 @@ export default function watchers(element: HTMLElement) { lichess.pubsub.on('socket.in.crowd', data => set(data.watchers || data)); - const set = (data: Data) => { + const set = (data: Data): void => { watchersData = data; - if (!data || !data.nb) return $element.addClass('none'); + if (!data || !data.nb) { + $element.addClass('none'); + return; + } $numberEl.text('' + data.nb); diff --git a/ui/site/src/component/widget.ts b/ui/site/src/component/widget.ts index 9b111130dd..295b873a7b 100644 --- a/ui/site/src/component/widget.ts +++ b/ui/site/src/component/widget.ts @@ -1,7 +1,7 @@ import * as data from 'common/data'; const widget = (name: string, prototype: any) => { - const constructor = ($[name] = function (options: any, element: HTMLElement) { + const constructor: any = (($ as any)[name] = function (options: any, element: HTMLElement) { const self: any = this; self.element = $(element); (element as any)[name] = this; @@ -9,7 +9,7 @@ const widget = (name: string, prototype: any) => { self._create(); }); constructor.prototype = prototype; - $.fn[name] = function (method: string) { + ($.fn as any)[name] = function (method: string) { const args = Array.prototype.slice.call(arguments, 1); if (typeof method === 'string') this.each(function (this: HTMLElement) { diff --git a/ui/site/src/coordinate.ts b/ui/site/src/coordinate.ts index 3f46bfd4e3..fc88981110 100644 --- a/ui/site/src/coordinate.ts +++ b/ui/site/src/coordinate.ts @@ -3,6 +3,7 @@ import { sparkline } from '@fnando/sparkline'; import throttle from 'common/throttle'; import resizeHandle from 'common/resize'; import * as cg from 'chessground/types'; +import { Api as ChessgroundApi } from 'chessground/api'; type CoordModifier = 'new' | 'next' | 'current' | 'resolved'; @@ -12,7 +13,7 @@ lichess.load.then(() => { const $board = $('.coord-trainer__board .cg-wrap'); const $coordsSvg = $('.coords-svg'); const $coordTexts = $coordsSvg.find('.coord text'); - let ground; + let ground: ChessgroundApi; const $side = $('.coord-trainer__side'); const $right = $('.coord-trainer__table'); const $bar = $trainer.find('.progress_bar'); @@ -25,9 +26,9 @@ lichess.load.then(() => { const tickDelay = 50; const resizePref = $trainer.data('resize-pref'); let colorPref = $trainer.data('color-pref'); - let color; - let startAt, score; - let wrongTimeout; + let color: Color; + let startAt: Date, score: number; + let wrongTimeout: number; let ply = 0; const showColor = function () { @@ -127,7 +128,7 @@ lichess.load.then(() => { $coordTexts.text(''); }; - const newCoord = function (prevCoord) { + const newCoord = function (prevCoord: Key): Key { // disallow the previous coordinate's row or file from being selected let files = 'abcdefgh'; const fileIndex = files.indexOf(prevCoord[0]); @@ -137,9 +138,8 @@ lichess.load.then(() => { const rowIndex = rows.indexOf(prevCoord[1]); rows = rows.slice(0, rowIndex) + rows.slice(rowIndex + 1, 8); - return ( - files[Math.round(Math.random() * (files.length - 1))] + rows[Math.round(Math.random() * (rows.length - 1))] - ); + return (files[Math.round(Math.random() * (files.length - 1))] + + rows[Math.round(Math.random() * (rows.length - 1))]) as Key; }; const coordClass = (modifier: CoordModifier) => `coord--${modifier}`; @@ -152,7 +152,7 @@ lichess.load.then(() => { coordEl('current').removeClass(coordClass('current')).addClass(coordClass('resolved')); coordEl('next').removeClass(coordClass('next')).addClass(coordClass('current')); - coordTextEl('new').text(newCoord(coordTextEl('current').text())); + coordTextEl('new').text(newCoord(coordTextEl('current').text() as Key)); coordEl('new').removeClass(coordClass('new')).addClass(coordClass('next')); resolvedEl.removeClass(coordClass('resolved')).addClass(coordClass('new')).appendTo($coordsSvg); @@ -165,7 +165,7 @@ lichess.load.then(() => { $trainer.removeClass('wrong'); ground.set({ events: { - select: false, + select: undefined, }, }); if (scoreUrl) @@ -181,7 +181,7 @@ lichess.load.then(() => { }; const tick = function () { - const spent = Math.min(duration, new Date().getTime() - startAt); + const spent = Math.min(duration, new Date().getTime() - +startAt); const left = ((duration - spent) / 1000).toFixed(1); if (+left < 10) { $timer.addClass('hurry'); @@ -203,7 +203,7 @@ lichess.load.then(() => { clearCoords(); centerRight(); score = 0; - $score.text(score); + $score.text(score.toString()); $bar.css('width', 0); setTimeout(function () { startAt = new Date(); @@ -213,7 +213,7 @@ lichess.load.then(() => { const hit = key == coordEl('current').text(); if (hit) { score++; - $score.text(score); + $score.text(score.toString()); advanceCoords(); } else { clearTimeout(wrongTimeout); diff --git a/ui/site/src/forum.ts b/ui/site/src/forum.ts index cc59fbc4a2..eb63642f0a 100644 --- a/ui/site/src/forum.ts +++ b/ui/site/src/forum.ts @@ -57,7 +57,7 @@ lichess.load.then(() => { [ { match: /(^|\s)@(|[a-zA-Z_-][\w-]{0,19})$/, - search: function (term: string, callback) { + search: function (term: string, callback: (names: string[]) => void) { // Initially we only autocomplete by participants in the thread. As the user types more, // we can autocomplete against all users on the site. threadParticipants.then(function (participants) { @@ -77,7 +77,7 @@ lichess.load.then(() => { } }); }, - replace: mention => '$1@' + mention + ' ', + replace: (mention: string) => '$1@' + mention + ' ', }, ], { diff --git a/ui/site/src/gameSearch.ts b/ui/site/src/gameSearch.ts index e19244feb6..7398bef6b7 100644 --- a/ui/site/src/gameSearch.ts +++ b/ui/site/src/gameSearch.ts @@ -14,9 +14,9 @@ lichess.load.then(() => { return us; } - function userChoices(row) { + function userChoices(row: HTMLTableRowElement) { const options = [""]; - const isSelected = function (row, rowClassName, user, dataKey) { + const isSelected = function (row: HTMLTableRowElement, rowClassName: string, user: string, dataKey: string) { const player = $form.data(dataKey); return row.classList.contains(rowClassName) && player.length && user == player ? 'selected' : ''; }; diff --git a/ui/site/src/modActivity.ts b/ui/site/src/modActivity.ts index 6c41382777..e1ef605088 100644 --- a/ui/site/src/modActivity.ts +++ b/ui/site/src/modActivity.ts @@ -74,7 +74,7 @@ export function queues(data: any) { const cfg = merge( { ...conf(room.name, data.common.xaxis), - series: room.series.map(s => ({ + series: room.series.map((s: any) => ({ ...s, name: `Score: ${s.name}`, })), diff --git a/ui/site/src/teamBattleForm.ts b/ui/site/src/teamBattleForm.ts index c81ca9fb16..587504d3e0 100644 --- a/ui/site/src/teamBattleForm.ts +++ b/ui/site/src/teamBattleForm.ts @@ -23,9 +23,9 @@ lichess.load.then(() => { id: 'team', match: /(^|\s)(.+)$/, index: 2, - search(term: string, callback: (res: any[]) => void) { + search(term: string, callback: (res: Team[]) => void) { xhr.json(xhr.url('/team/autocomplete', { term }), { cache: 'default' }).then( - res => { + (res: Team[]) => { const current = textarea.value .split('\n') .map(t => t.split(' ')[0]) diff --git a/ui/site/src/userComplete.ts b/ui/site/src/userComplete.ts index 7676980ae1..52d5ba67b4 100644 --- a/ui/site/src/userComplete.ts +++ b/ui/site/src/userComplete.ts @@ -2,16 +2,16 @@ import * as xhr from 'common/xhr'; import complete from 'common/complete'; import debounce from 'debounce-promise'; -interface Result extends LightUser { - online: boolean; +export interface Result { + result: LightUserOnline[]; } interface Opts { input: HTMLInputElement; tag?: 'a' | 'span'; minLength?: number; - populate?: (result: Result) => string; - onSelect?: (result: Result) => void; + populate?: (result: LightUserOnline) => string; + onSelect?: (result: LightUserOnline) => void; focus?: boolean; friend?: boolean; tour?: string; @@ -31,14 +31,14 @@ export default function (opts: Opts): void { object: 1, }) ) - .then(r => ({ term, ...r })), + .then((r: Result) => ({ term, ...r })), 150 ); - complete({ + complete({ input: opts.input, fetch: t => debounced(t).then(({ term, result }) => (t == term ? result : Promise.reject('Debounced ' + t))), - render(o: Result) { + render(o: LightUserOnline) { const tag = opts.tag || 'a'; return ( '<' + diff --git a/ui/site/tsconfig.json b/ui/site/tsconfig.json index 1ba3996e6d..83334f4fa3 100644 --- a/ui/site/tsconfig.json +++ b/ui/site/tsconfig.json @@ -1,7 +1,6 @@ { "extends": "../tsconfig.base.json", "compilerOptions": { - "noImplicitAny": false, "noImplicitReturns": false, "esModuleInterop": true } diff --git a/ui/site/types/tablesort.d.ts b/ui/site/types/tablesort.d.ts new file mode 100644 index 0000000000..4567b7839d --- /dev/null +++ b/ui/site/types/tablesort.d.ts @@ -0,0 +1 @@ +declare module 'tablesort';