refactor(large): disallow implicit any

Signed-off-by: Varun Patil <radialapps@gmail.com>
pull/877/head
Varun Patil 2023-10-11 22:56:53 -07:00
parent bcd16a9cb0
commit 313ba6c3c2
21 changed files with 119 additions and 87 deletions

13
package-lock.json generated
View File

@ -38,6 +38,7 @@
"@nextcloud/webpack-vue-config": "^6.0.0",
"@playwright/test": "^1.39.0",
"@types/hammerjs": "^2.0.42",
"@types/justified-layout": "^4.1.1",
"@types/luxon": "^3.3.2",
"@types/url-parse": "^1.4.9",
"@types/videojs-contrib-quality-levels": "^2.0.2",
@ -2534,6 +2535,12 @@
"integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==",
"peer": true
},
"node_modules/@types/justified-layout": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/@types/justified-layout/-/justified-layout-4.1.1.tgz",
"integrity": "sha512-/ZJGVeDif6EHRzK3kUifyOekGJcBXD1s/eRYAYgkJHI4QAkohz62E0PSMbFrGpOdTulPWRgOAh1mFZbYw9a9iQ==",
"dev": true
},
"node_modules/@types/leaflet": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/@types/leaflet/-/leaflet-1.9.0.tgz",
@ -13688,6 +13695,12 @@
"integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==",
"peer": true
},
"@types/justified-layout": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/@types/justified-layout/-/justified-layout-4.1.1.tgz",
"integrity": "sha512-/ZJGVeDif6EHRzK3kUifyOekGJcBXD1s/eRYAYgkJHI4QAkohz62E0PSMbFrGpOdTulPWRgOAh1mFZbYw9a9iQ==",
"dev": true
},
"@types/leaflet": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/@types/leaflet/-/leaflet-1.9.0.tgz",

View File

@ -66,6 +66,7 @@
"@nextcloud/webpack-vue-config": "^6.0.0",
"@playwright/test": "^1.39.0",
"@types/hammerjs": "^2.0.42",
"@types/justified-layout": "^4.1.1",
"@types/luxon": "^3.3.2",
"@types/url-parse": "^1.4.9",
"@types/videojs-contrib-quality-levels": "^2.0.2",

View File

@ -278,7 +278,7 @@ export default defineComponent({
name: this.t('memories', 'Info'),
icon: 'icon-details',
mount(el, fileInfo, context) {
mount(el: HTMLElement, fileInfo: { id: string | number }, context: any) {
this.metadataComponent?.$destroy?.();
this.metadataComponent = new Vue({
render: (h) => h(Metadata),
@ -287,7 +287,7 @@ export default defineComponent({
this.metadataComponent.$mount(el);
this.metadataComponent.$children[0].update(Number(fileInfo.id));
},
update(fileInfo) {
update(fileInfo: { id: string | number }) {
this.metadataComponent.$children[0].update(Number(fileInfo.id));
},
destroy() {

View File

@ -27,11 +27,24 @@ import './styles/global.scss';
// Global exposed variables
declare global {
var mode: 'admin' | 'user';
var __webpack_nonce__: string;
var __webpack_public_path__: string;
var vueroute: () => Route;
var OC: Nextcloud.Common.OC;
var OCP: Nextcloud.Common.OCP;
var OCA: {
Files?: {
Sidebar?: any;
App?: any;
};
Theming?: {
name: string;
enabledThemes: any[];
};
};
var mode: 'admin' | 'user';
var vueroute: () => Route;
var mModals: {
editMetadata: (photos: IPhoto[], sections?: number[]) => void;
@ -62,13 +75,12 @@ declare global {
var windowInnerWidth: number; // cache
var windowInnerHeight: number; // cache
var __webpack_nonce__: string;
var __webpack_public_path__: string;
var vidjs: typeof videojsType;
var Plyr: typeof PlyrType;
var videoClientId: string;
var videoClientIdPersistent: string;
var photoswipe: unknown;
}
// Allow global access to the router

View File

@ -113,7 +113,7 @@ export default defineComponent({
}
},
async update(key: keyof ISystemConfig, value: any = null) {
async update<K extends keyof ISystemConfig>(key: K, value: ISystemConfig[K] | null = null) {
if (!this.config?.hasOwnProperty(key)) {
console.error('Unknown setting', key);
return;
@ -121,7 +121,7 @@ export default defineComponent({
// Get final value
value ??= this.config[key];
this.config[key as string] = value;
this.config[key] = value;
try {
this.loading++;

View File

@ -265,7 +265,7 @@ export default defineComponent({
},
});
this.currentSearchResults = response.data.ocs.data.map((collaborator) => {
this.currentSearchResults = response.data.ocs.data.map((collaborator: any) => {
switch (collaborator.source) {
case 'users':
return {
@ -394,7 +394,7 @@ export default defineComponent({
}, 10000);
},
selectEntity(collaboratorKey) {
selectEntity(collaboratorKey: string) {
if (this.selectedCollaboratorsKeys.includes(collaboratorKey)) {
return;
}
@ -403,7 +403,7 @@ export default defineComponent({
this.selectedCollaboratorsKeys.push(collaboratorKey);
},
unselectEntity(collaboratorKey) {
unselectEntity(collaboratorKey: string) {
const index = this.selectedCollaboratorsKeys.indexOf(collaboratorKey);
if (index === -1) {

View File

@ -216,10 +216,7 @@ export default defineComponent({
this.loading = true;
let album = { ...this.album };
if (this.album.basename !== this.albumName) {
album = await dav.renameAlbum(this.album, {
currentAlbumName: this.album.basename,
newAlbumName: this.albumName,
});
album = await dav.renameAlbum(this.album, this.album.basename, this.albumName);
}
if (this.album.location !== this.albumLocation) {
album.location = await dav.updateAlbum(this.album, {

View File

@ -23,14 +23,14 @@
<script lang="ts">
import { defineComponent } from 'vue';
import { IPhoto } from '../../types';
import { IExif, IPhoto } from '../../types';
const NcTextField = () => import('@nextcloud/vue/dist/Components/NcTextField');
import { translate as t } from '@nextcloud/l10n';
interface IField {
field: string;
field: keyof IExif;
label: string;
}
@ -51,8 +51,8 @@ export default defineComponent({
},
data: () => ({
exif: null! as Record<string, string>,
dirty: {} as Record<string, boolean>,
exif: null as Record<keyof IExif, string> | null,
dirty: {} as Record<keyof IExif, boolean>,
fields: [
{
@ -87,38 +87,29 @@ export default defineComponent({
}),
mounted() {
let exif = {};
const exif = {} as NonNullable<typeof this.exif>;
for (const field of this.fields) {
exif[field.field] = null;
this.dirty[field.field] = false;
}
const photos = this.photos as IPhoto[];
for (const photo of photos) {
if (!photo.imageInfo?.exif) {
continue;
}
for (const field of this.fields) {
const ePhoto = photo.imageInfo?.exif[field.field];
const eCurr = exif[field.field];
if (ePhoto && (eCurr === null || ePhoto === eCurr)) {
exif[field.field] = String(ePhoto);
// Check if all photos have the same value for this field
const first = this.photos[0]?.imageInfo?.exif?.[field.field];
if (this.photos.every((p) => p.imageInfo?.exif?.[field.field] === first)) {
exif[field.field] = String(first ?? String());
} else {
exif[field.field] = String();
}
}
}
this.exif = exif;
},
methods: {
result() {
const diff = {};
const diff = {} as Record<keyof IExif, string>;
for (const field of this.fields) {
if (this.dirty[field.field]) {
diff[field.field] = this.exif[field.field];
diff[field.field] = this.exif![field.field];
}
}
return diff;
@ -133,7 +124,7 @@ export default defineComponent({
},
reset(field: IField) {
this.exif[field.field] = '';
this.exif![field.field] = '';
this.dirty[field.field] = false;
},
},

View File

@ -23,7 +23,7 @@ import LandscapeIcon from '@scaleflex/icons/landscape';
import PortraitIcon from '@scaleflex/icons/portrait';
import SquareIcon from '@scaleflex/icons/square';
let TABS, TOOLS: any;
let TABS: any, TOOLS: any;
type FilerobotImageEditor = import('filerobot-image-editor').default;
let FilerobotImageEditor: typeof import('filerobot-image-editor').default;
@ -151,7 +151,7 @@ export default defineComponent({
hasHighContrastEnabled(): boolean {
const themes = globalThis.OCA?.Theming?.enabledThemes || [];
return themes.find((theme) => theme.indexOf('highcontrast') !== -1);
return themes.find((theme: any) => theme.indexOf('highcontrast') !== -1);
},
themeDataAttr(): Record<string, boolean> {
@ -209,7 +209,7 @@ export default defineComponent({
return img;
},
onClose(closingReason, haveNotSavedChanges) {
onClose(closingReason: any, haveNotSavedChanges: boolean) {
if (haveNotSavedChanges) {
this.onExitWithoutSaving();
return;
@ -303,7 +303,7 @@ export default defineComponent({
},
// Key Handlers, override default Viewer arrow and escape key
handleKeydown(event) {
handleKeydown(event: KeyboardEvent) {
event.stopImmediatePropagation();
// escape key
if (event.key === 'Escape') {

View File

@ -30,7 +30,7 @@ class LivePhotoContentSetup {
}
}
onContentLoad(e) {
onContentLoad(e: PsEvent) {
const content: PsContent = e.content;
if (!isLiveContent(content)) return;

View File

@ -30,7 +30,7 @@ type PsVideoEvent = PsEvent & {
* Check if slide has video content
*/
export function isVideoContent(content: unknown): content is VideoContent {
return typeof content === 'object' && content?.['data']?.['type'] === 'video';
return typeof content === 'object' && (<any>content)?.['data']?.['type'] === 'video';
}
class VideoContentSetup {
@ -235,7 +235,7 @@ class VideoContentSetup {
playWithDelay();
});
content.videojs.qualityLevels?.()?.on('addqualitylevel', (e) => {
content.videojs.qualityLevels?.()?.on('addqualitylevel', (e: any) => {
if (e.qualityLevel?.label?.includes('max.m3u8')) {
// This is the highest quality level
// and guaranteed to be the last one
@ -448,7 +448,7 @@ class VideoContentSetup {
this.destroyVideo(content);
}
onContentResize(e) {
onContentResize(e: PsVideoEvent & { width: number; height: number }) {
if (isVideoContent(e.content)) {
e.preventDefault();
@ -461,12 +461,12 @@ class VideoContentSetup {
content.element.style.height = height + 'px';
}
if (content.slide && content.slide.placeholder) {
// override placeholder size, so it more accurately matches the video
const placeholderElStyle = content.slide.placeholder.element.style;
placeholderElStyle.transform = 'none';
placeholderElStyle.width = width + 'px';
placeholderElStyle.height = height + 'px';
const phStyle = content.placeholder?.element?.style;
if (phStyle) {
phStyle.transform = 'none';
phStyle.width = width + 'px';
phStyle.height = height + 'px';
}
}
}

View File

@ -487,8 +487,10 @@ export default defineComponent({
globalThis.photoswipe = this.photoswipe;
// Monkey patch for focus trapping in sidebar
const _onFocusIn = this.photoswipe.keyboard['_onFocusIn'];
this.photoswipe.keyboard['_onFocusIn'] = (e: FocusEvent) => {
const psKeyboard = this.photoswipe.keyboard as any;
const _onFocusIn = psKeyboard['_onFocusIn'];
console.assert(_onFocusIn, 'Missing _onFocusIn for monkey patch');
psKeyboard['_onFocusIn'] = (e: FocusEvent) => {
if (
e.target instanceof HTMLElement &&
e.target.closest(['#app-sidebar-vue', '.v-popper__popper', '.modal-mask', '.oc-dialog'].join(','))

View File

@ -31,10 +31,10 @@ export default defineComponent({
methods: {
async refreshFromConfig() {
const config = await staticConfig.getAll();
const changed = Object.keys(config).filter((key) => config[key] !== this.config[key]);
const changed = Object.keys(config).filter(<K extends keyof IConfig>(key: K) => config[key] !== this.config[key]);
if (changed.length === 0) return;
changed.forEach((key) => (this.config[key] = config[key]));
changed.forEach(<K extends keyof IConfig>(key: K) => (this.config[key] = config[key]));
utils.bus.emit(eventName, null);
},

View File

@ -190,4 +190,4 @@ export type NativeX = {
};
/** The native interface is a global object that is injected by the native app. */
export const nativex: NativeX = globalThis.nativex;
export const nativex: NativeX = (<any>globalThis).nativex;

View File

@ -212,7 +212,7 @@ export async function getAlbum(user: string, name: string, extraProps = {}) {
}
/** Rename an album */
export async function renameAlbum(album: any, { currentAlbumName, newAlbumName }) {
export async function renameAlbum(album: any, currentAlbumName: string, newAlbumName: string) {
const newAlbum = { ...album, basename: newAlbumName };
try {
await client.moveFile(

View File

@ -28,7 +28,7 @@ import { generateRemoteUrl } from '@nextcloud/router';
// Monkey business
import * as rq from 'webdav/dist/node/request';
const prepareRequestOptionsOld = rq.prepareRequestOptions.bind(rq);
(<any>rq).prepareRequestOptions = (requestOptions, context, userOptions) => {
(<any>rq).prepareRequestOptions = (requestOptions: any, context: any, userOptions: any) => {
requestOptions.method = userOptions.method || requestOptions.method;
return prepareRequestOptionsOld(requestOptions, context, userOptions);
};

View File

@ -48,9 +48,9 @@ class StaticConfig {
}
// Assign to existing default
for (const key in this.config) {
this.default![key] = this.config[key];
this.setLs(key as keyof IConfig, this.config[key]);
for (const k in this.config) {
const key = k as keyof IConfig;
this.setLs(key, this.config[key]);
}
// Resolve all promises
@ -141,17 +141,20 @@ class StaticConfig {
album_list_sort: 1,
};
for (const key in config) {
const val = this.storage.getItem(`memories_${key}`);
if (val !== null) {
const set = <K extends keyof IConfig, V extends IConfig[K]>(key: K, value: string | null) => {
if (value == null) return;
if (typeof config[key] === 'boolean') {
config[key] = val === 'true';
config[key] = (value === 'true') as V;
} else if (typeof config[key] === 'number') {
config[key] = Number(val);
config[key] = Number(value) as V;
} else {
config[key] = val;
}
config[key] = value as V;
}
};
for (const key in config) {
set(key as keyof IConfig, this.storage.getItem(`memories_${key}`));
}
this.default = config;

View File

@ -81,7 +81,7 @@ export function randomSubarray<T>(arr: T[], size: number): T[] {
}
/** Set a timer that renews if existing */
export function setRenewingTimeout<T>(ctx: T, name: string, callback: (() => void) | null, delay: number): void {
export function setRenewingTimeout(ctx: any, name: string, callback: (() => void) | null, delay: number): void {
if (ctx[name]) window.clearTimeout(ctx[name]);
ctx[name] = window.setTimeout(() => {
ctx[name] = 0;

19
src/shims.d.ts vendored 100644
View File

@ -0,0 +1,19 @@
declare module '*.svg' {
const content: string;
export default content;
}
declare module '*.vue' {
import type { defineComponent } from 'vue';
const Component: ReturnType<typeof defineComponent>;
export default Component;
}
// External components cannot be imported with .vue extension
declare module '@nextcloud/vue/dist/Components/*' {
import type { defineComponent } from 'vue';
const Component: ReturnType<typeof defineComponent>;
export default Component;
}
declare module 'vue-virtual-scroller';

10
src/vue-shims.d.ts vendored
View File

@ -1,10 +0,0 @@
declare module '*.vue' {
import type { defineComponent } from 'vue';
const Component: ReturnType<typeof defineComponent>;
export default Component;
}
declare module '*.svg' {
const content: string;
export default content;
}

View File

@ -1,6 +1,9 @@
{
"compilerOptions": {
"lib": ["dom", "es2017"],
"lib": [
"dom",
"es2017"
],
"target": "ES2017",
"module": "es2020",
"moduleResolution": "node",
@ -9,6 +12,7 @@
"jsx": "preserve",
"useDefineForClassFields": true,
"noImplicitThis": true,
"noImplicitAny": true,
"esModuleInterop": true,
"strictNullChecks": true
},