Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplify type checking for objects #11831

Merged
merged 2 commits into from
Jan 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,14 @@
import { SelectionService } from '@theia/core/lib/common/selection-service';
import { SelectionCommandHandler } from '@theia/core/lib/common/selection-command-handler';
import { ResourceFileEdit, ResourceTextEdit } from '@theia/monaco-editor-core/esm/vs/editor/browser/services/bulkEditService';
import { isObject } from '@theia/core/lib/common';

export interface BulkEditNodeSelection {
bulkEdit: ResourceFileEdit | ResourceTextEdit;
}
export namespace BulkEditNodeSelection {
export function is(arg: unknown): arg is BulkEditNodeSelection {
return !!arg && typeof arg === 'object' && ('bulkEdit' in arg);
return isObject(arg) && 'bulkEdit' in arg;
}

export class CommandHandler extends SelectionCommandHandler<BulkEditNodeSelection> {
Expand Down
1 change: 1 addition & 0 deletions packages/core/shared/reflect-metadata/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from 'reflect-metadata';
1 change: 1 addition & 0 deletions packages/core/shared/reflect-metadata/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('reflect-metadata');
4 changes: 2 additions & 2 deletions packages/core/src/browser/frontend-application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
// *****************************************************************************

import { inject, injectable, named } from 'inversify';
import { ContributionProvider, CommandRegistry, MenuModelRegistry, isOSX, BackendStopwatch, LogLevel, Stopwatch } from '../common';
import { ContributionProvider, CommandRegistry, MenuModelRegistry, isOSX, BackendStopwatch, LogLevel, Stopwatch, isObject } from '../common';
import { MaybePromise } from '../common/types';
import { KeybindingRegistry } from './keybinding';
import { Widget } from './widgets';
Expand Down Expand Up @@ -101,7 +101,7 @@ export interface OnWillStopAction<T = unknown> {

export namespace OnWillStopAction {
export function is(candidate: unknown): candidate is OnWillStopAction {
return typeof candidate === 'object' && !!candidate && 'action' in candidate && 'reason' in candidate;
return isObject(candidate) && 'action' in candidate && 'reason' in candidate;
}
}

Expand Down
5 changes: 3 additions & 2 deletions packages/core/src/browser/label-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,16 @@
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
// *****************************************************************************
import { injectable } from 'inversify';
import { isObject, isString } from '../common';

export interface LabelIcon {
name: string;
animation?: string;
}

export namespace LabelIcon {
export function is(val: object): val is LabelIcon {
return 'name' in val;
export function is(val: unknown): val is LabelIcon {
return isObject<LabelIcon>(val) && isString(val.name);
}
}

Expand Down
5 changes: 2 additions & 3 deletions packages/core/src/browser/label-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@ import { inject, injectable, named, postConstruct } from 'inversify';
import * as fileIcons from 'file-icons-js';
import URI from '../common/uri';
import { ContributionProvider } from '../common/contribution-provider';
import { Prioritizeable } from '../common/types';
import { Event, Emitter, Disposable, Path } from '../common';
import { Event, Emitter, Disposable, isObject, Path, Prioritizeable } from '../common';
import { FrontendApplicationContribution } from './frontend-application';
import { EnvVariablesServer } from '../common/env-variables/env-variables-protocol';
import { ResourceLabelFormatter, ResourceLabelFormatting } from '../common/label-protocol';
Expand Down Expand Up @@ -99,7 +98,7 @@ export interface URIIconReference {
}
export namespace URIIconReference {
export function is(element: unknown): element is URIIconReference {
return !!element && typeof element === 'object' && 'kind' in element && (element as URIIconReference).kind === 'uriIconReference';
return isObject(element) && element.kind === 'uriIconReference';
}
export function create(id: URIIconReference['id'], uri?: URI): URIIconReference {
return { kind: 'uriIconReference', id, uri };
Expand Down
13 changes: 6 additions & 7 deletions packages/core/src/browser/navigatable-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
// *****************************************************************************

import URI from '../common/uri';
import { MaybeArray } from '../common/types';
import { URI, isObject, MaybeArray } from '../common';
import { Widget, BaseWidget } from './widgets';

/**
Expand All @@ -34,7 +33,7 @@ export interface Navigatable {

export namespace Navigatable {
export function is(arg: unknown): arg is Navigatable {
return !!arg && typeof arg === 'object' && 'getResourceUri' in arg && 'createMoveToUri' in arg;
return isObject(arg) && 'getResourceUri' in arg && 'createMoveToUri' in arg;
}
}

Expand Down Expand Up @@ -71,12 +70,12 @@ export namespace NavigatableWidget {
}

export interface NavigatableWidgetOptions {
kind: 'navigatable',
uri: string,
counter?: number,
kind: 'navigatable';
uri: string;
counter?: number;
}
export namespace NavigatableWidgetOptions {
export function is(arg: unknown): arg is NavigatableWidgetOptions {
return !!arg && typeof arg === 'object' && 'kind' in arg && (arg as NavigatableWidgetOptions).kind === 'navigatable';
return isObject(arg) && arg.kind === 'navigatable';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

import { inject, injectable, postConstruct } from 'inversify';
import { PreferenceSchema } from '../../common/preferences/preference-schema';
import { Disposable, DisposableCollection, Emitter, Event, MaybePromise } from '../../common';
import { Disposable, DisposableCollection, Emitter, Event, isObject, MaybePromise } from '../../common';
import { PreferenceChangeEvent, PreferenceEventEmitter, PreferenceProxy, PreferenceProxyOptions, PreferenceRetrieval } from './preference-proxy';
import { PreferenceChange, PreferenceChangeImpl, PreferenceChanges, PreferenceScope, PreferenceService } from './preference-service';
import { JSONValue } from '@phosphor/coreutils';
Expand Down Expand Up @@ -103,7 +103,9 @@ export class InjectablePreferenceProxy<T extends Record<string, JSONValue>> impl
}

get(target: unknown, property: string, receiver: unknown): unknown {
if (typeof property !== 'string') { throw new Error(`Unexpected property: ${String(property)}`); }
if (typeof property !== 'string') {
throw new Error(`Unexpected property: ${String(property)}`);
}
const preferenceName = this.prefix + property;
if (this.schema && (this.isFlat || !property.includes('.')) && this.schema.properties[preferenceName]) {
const { overrideIdentifier } = this;
Expand Down Expand Up @@ -143,7 +145,7 @@ export class InjectablePreferenceProxy<T extends Record<string, JSONValue>> impl
} while (parentSegment && value === undefined);

let segment;
while (typeof value === 'object' && (segment = segments.pop())) {
while (isObject(value) && (segment = segments.pop())) {
value = value[segment];
}
return segments.length ? undefined : value;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import { FrontendApplicationConfigProvider } from '../frontend-application-confi
import { FrontendApplicationConfig } from '@theia/application-package/lib/application-props';
import { bindPreferenceConfigurations, PreferenceConfigurations } from './preference-configurations';
export { PreferenceSchema, PreferenceSchemaProperties, PreferenceDataSchema, PreferenceItem, PreferenceSchemaProperty, PreferenceDataProperty };
import { Mutable } from '../../common/types';
import { isObject, Mutable } from '../../common/types';
import { PreferenceLanguageOverrideService } from './preference-language-override-service';
import { JSONValue } from '@phosphor/coreutils';

Expand Down Expand Up @@ -80,7 +80,7 @@ export interface FrontendApplicationPreferenceConfig extends FrontendApplication
}
export namespace FrontendApplicationPreferenceConfig {
export function is(config: FrontendApplicationConfig): config is FrontendApplicationPreferenceConfig {
return 'preferences' in config && typeof config['preferences'] === 'object';
return isObject(config.preferences);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
// *****************************************************************************

import { injectable } from 'inversify';
import { escapeRegExpCharacters } from '../../common';
import { escapeRegExpCharacters, isObject } from '../../common';
import { PreferenceSchemaProperties } from '../../common/preferences/preference-schema';

export interface OverridePreferenceName {
Expand All @@ -24,7 +24,7 @@ export interface OverridePreferenceName {
}
export namespace OverridePreferenceName {
export function is(arg: unknown): arg is OverridePreferenceName {
return !!arg && typeof arg === 'object' && 'preferenceName' in arg && 'overrideIdentifier' in arg;
return isObject(arg) && 'preferenceName' in arg && 'overrideIdentifier' in arg;
}
}

Expand Down
12 changes: 4 additions & 8 deletions packages/core/src/browser/preferences/preference-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import debounce = require('p-debounce');
import { injectable, inject } from 'inversify';
import { JSONExt, JSONValue } from '@phosphor/coreutils';
import URI from '../../common/uri';
import { Disposable, DisposableCollection, Emitter, Event } from '../../common';
import { Disposable, DisposableCollection, Emitter, Event, isObject } from '../../common';
import { Deferred } from '../../common/promise-util';
import { PreferenceScope } from './preference-scope';
import { PreferenceLanguageOverrideService } from './preference-language-override-service';
Expand Down Expand Up @@ -253,16 +253,12 @@ export abstract class PreferenceProvider implements Disposable {

protected getParsedContent(jsonData: any): { [key: string]: any } {
const preferences: { [key: string]: any } = {};
if (typeof jsonData !== 'object') {
if (!isObject(jsonData)) {
return preferences;
}
// eslint-disable-next-line guard-for-in
for (const preferenceName in jsonData) {
const preferenceValue = jsonData[preferenceName];
for (const [preferenceName, preferenceValue] of Object.entries(jsonData)) {
if (this.preferenceOverrideService.testOverrideValue(preferenceName, preferenceValue)) {
// eslint-disable-next-line guard-for-in
for (const overriddenPreferenceName in preferenceValue) {
const overriddenValue = preferenceValue[overriddenPreferenceName];
for (const [overriddenPreferenceName, overriddenValue] of Object.entries(preferenceValue)) {
preferences[`${preferenceName}.${overriddenPreferenceName}`] = overriddenValue;
}
} else {
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/browser/preferences/preference-proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

/* eslint-disable @typescript-eslint/no-explicit-any */

import { Disposable, Event, MaybePromise } from '../../common';
import { Disposable, Event, isObject, MaybePromise } from '../../common';
import { PreferenceService } from './preference-service';
import { PreferenceSchema } from './preference-contribution';
import { PreferenceScope } from './preference-scope';
Expand Down Expand Up @@ -332,7 +332,7 @@ export function createPreferenceProxy<T>(preferences: PreferenceService, promise
} while (parentSegment && value === undefined);

let segment;
while (typeof value === 'object' && (segment = segments.pop())) {
while (isObject(value) && (segment = segments.pop())) {
value = value[segment];
}
return segments.length ? undefined : value;
Expand Down
5 changes: 3 additions & 2 deletions packages/core/src/browser/saveable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { Key } from './keyboard/keys';
import { AbstractDialog } from './dialogs';
import { waitForClosed } from './widgets';
import { nls } from '../common/nls';
import { isObject } from '../common';

export interface Saveable {
readonly dirty: boolean;
Expand Down Expand Up @@ -60,10 +61,10 @@ export namespace Saveable {

export type Snapshot = { value: string } | { read(): string | null };
export function isSource(arg: unknown): arg is SaveableSource {
return typeof arg === 'object' && !!arg && is((arg as SaveableSource).saveable);
return isObject<SaveableSource>(arg) && is(arg.saveable);
}
export function is(arg: unknown): arg is Saveable {
return typeof arg === 'object' && !!arg && 'dirty' in arg && 'onDirtyChanged' in arg;
return isObject(arg) && 'dirty' in arg && 'onDirtyChanged' in arg;
}
export function get(arg: unknown): Saveable | undefined {
if (is(arg)) {
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/browser/shell/application-shell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import {
} from '@phosphor/widgets';
import { Message } from '@phosphor/messaging';
import { IDragEvent } from '@phosphor/dragdrop';
import { RecursivePartial, Event as CommonEvent, DisposableCollection, Disposable, environment } from '../../common';
import { RecursivePartial, Event as CommonEvent, DisposableCollection, Disposable, environment, isObject } from '../../common';
import { animationFrame } from '../browser';
import { Saveable, SaveableWidget, SaveOptions, SaveableSource } from '../saveable';
import { StatusBarImpl, StatusBarEntry, StatusBarAlignment } from '../status-bar/status-bar';
Expand Down Expand Up @@ -2108,7 +2108,7 @@ export namespace ApplicationShell {

export namespace TrackableWidgetProvider {
export function is(widget: unknown): widget is TrackableWidgetProvider {
return !!widget && typeof widget === 'object' && 'getTrackableWidgets' in widget;
return isObject(widget) && 'getTrackableWidgets' in widget;
}
}

Expand Down
17 changes: 6 additions & 11 deletions packages/core/src/browser/shell/shell-layout-restorer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ import { ILogger } from '../../common/logger';
import { CommandContribution, CommandRegistry, Command } from '../../common/command';
import { ThemeService } from '../theming';
import { ContributionProvider } from '../../common/contribution-provider';
import { MaybePromise } from '../../common/types';
import { ApplicationShell, applicationShellLayoutVersion, ApplicationShellLayoutVersion } from './application-shell';
import { CommonCommands } from '../common-frontend-contribution';
import { WindowService } from '../window/window-service';
import { StopReason } from '../../common/frontend-application-state';
import { isFunction, isObject, MaybePromise } from '../../common';

/**
* A contract for widgets that want to store and restore their inner state, between sessions.
Expand All @@ -47,7 +47,7 @@ export interface StatefulWidget {

export namespace StatefulWidget {
export function is(arg: unknown): arg is StatefulWidget {
return !!arg && typeof arg === 'object' && typeof (arg as StatefulWidget).storeState === 'function' && typeof (arg as StatefulWidget).restoreState === 'function';
return isObject<StatefulWidget>(arg) && isFunction(arg.storeState) && isFunction(arg.restoreState);
}
}

Expand Down Expand Up @@ -232,11 +232,7 @@ export class ShellLayoutRestorer implements CommandContribution {
const parseContext = new ShellLayoutRestorer.ParseContext();
const layout = this.parse<ApplicationShell.LayoutData>(layoutData, parseContext);

// eslint-disable-next-line @typescript-eslint/no-explicit-any
let layoutVersion: number | any;
try {
layoutVersion = 'version' in layout && Number(layout.version);
} catch { /* no-op */ }
const layoutVersion = Number(layout.version);
if (typeof layoutVersion !== 'number' || Number.isNaN(layoutVersion)) {
throw new Error('could not resolve a layout version');
}
Expand Down Expand Up @@ -282,9 +278,8 @@ export class ShellLayoutRestorer implements CommandContribution {
});
}
return widgets;
} else if (value && typeof value === 'object' && !Array.isArray(value)) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const copy: any = {};
} else if (isObject<Record<string, WidgetDescription>>(value) && !Array.isArray(value)) {
const copy: Record<string, unknown> = {};
for (const p in value) {
if (this.isWidgetProperty(p)) {
parseContext.push(async context => {
Expand All @@ -306,7 +301,7 @@ export class ShellLayoutRestorer implements CommandContribution {
// don't catch exceptions, if one migration fails all should fail.
const migrated = await migration.onWillInflateWidget(desc, context);
if (migrated) {
if (migrated.innerWidgetState && typeof migrated.innerWidgetState !== 'string') {
if (isObject(migrated.innerWidgetState)) {
// in order to inflate nested widgets
migrated.innerWidgetState = JSON.stringify(migrated.innerWidgetState);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
// *****************************************************************************

import * as React from 'react';
import { ArrayUtils, Event, MenuPath } from '../../../common';
import { ArrayUtils, Event, isFunction, isObject, isString, MenuPath } from '../../../common';
import { Widget } from '../../widgets';

/** Items whose group is exactly 'navigation' will be rendered inline. */
Expand All @@ -27,13 +27,9 @@ export interface TabBarDelegator extends Widget {
}

export namespace TabBarDelegator {
export const is = (candidate?: Widget): candidate is TabBarDelegator => {
if (candidate) {
const asDelegator = candidate as TabBarDelegator;
return typeof asDelegator.getTabBarDelegate === 'function';
}
return false;
};
export function is(candidate?: Widget): candidate is TabBarDelegator {
return isObject<TabBarDelegator>(candidate) && isFunction(candidate.getTabBarDelegate);
}
}

interface RegisteredToolbarItem {
Expand Down Expand Up @@ -172,14 +168,13 @@ export namespace TabBarToolbarItem {
};

export function is(arg: unknown): arg is TabBarToolbarItem {
return !!arg && typeof arg === 'object' && 'command' in arg && typeof (arg as TabBarToolbarItem).command === 'string';
return isObject<TabBarToolbarItem>(arg) && isString(arg.command);
}

}

export namespace MenuToolbarItem {
export function getMenuPath(item: AnyToolbarItem): MenuPath | undefined {
const asDelegate = item as MenuToolbarItem;
return Array.isArray(asDelegate.menuPath) ? asDelegate.menuPath : undefined;
return Array.isArray(item.menuPath) ? item.menuPath : undefined;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ export class TabBarToolbar extends ReactWidget {
const classNames = [];
if (item.text) {
for (const labelPart of this.labelParser.parse(item.text)) {
if (typeof labelPart !== 'string' && LabelIcon.is(labelPart)) {
if (LabelIcon.is(labelPart)) {
const className = `fa fa-${labelPart.name}${labelPart.animation ? ' fa-' + labelPart.animation : ''}`;
classNames.push(...className.split(' '));
} else {
Expand Down
6 changes: 2 additions & 4 deletions packages/core/src/browser/source-tree/tree-source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,7 @@

import { ReactNode } from 'react';
import { injectable, unmanaged } from 'inversify';
import { Emitter, Event } from '../../common/event';
import { MaybePromise } from '../../common/types';
import { Disposable, DisposableCollection } from '../../common/disposable';
import { Disposable, DisposableCollection, Emitter, Event, isObject, MaybePromise } from '../../common';
import { TreeWidget } from '../tree';

export interface TreeElement {
Expand All @@ -39,7 +37,7 @@ export interface CompositeTreeElement extends TreeElement {
}
export namespace CompositeTreeElement {
export function is(element: unknown): element is CompositeTreeElement {
return !!element && typeof element === 'object' && 'getElements' in element;
return isObject(element) && 'getElements' in element;
}
export function hasElements(element: unknown): element is CompositeTreeElement {
return is(element) && element.hasElements !== false;
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/browser/status-bar/status-bar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ export class StatusBarImpl extends ReactWidget implements StatusBar {
const children: JSX.Element[] = [];

childStrings.forEach((val, key) => {
if (!(typeof val === 'string') && LabelIcon.is(val)) {
if (LabelIcon.is(val)) {
const animation = val.animation ? ` fa-${val.animation}` : '';
if (val.name.startsWith('codicon-')) {
children.push(<span key={key} className={`codicon ${val.name}${animation}`}></span>);
Expand Down
Loading