typing improvements

This commit is contained in:
Labhansh Agrawal 2020-06-19 18:21:34 +05:30 committed by Benjamin Staneck
parent c17c4cd7bf
commit d0e954def5
18 changed files with 56 additions and 50 deletions

View file

@ -21,9 +21,10 @@ class AutoUpdater extends EventEmitter implements Electron.AutoUpdater {
this.emit('checking-for-update'); this.emit('checking-for-update');
fetch(this.updateURL) fetch(this.updateURL)
.then((res): any => { .then((res) => {
if (res.status === 204) { if (res.status === 204) {
return this.emit('update-not-available'); this.emit('update-not-available');
return;
} }
// eslint-disable-next-line @typescript-eslint/camelcase // eslint-disable-next-line @typescript-eslint/camelcase
return res.json().then(({name, notes, pub_date}) => { return res.json().then(({name, notes, pub_date}) => {
@ -40,7 +41,7 @@ class AutoUpdater extends EventEmitter implements Electron.AutoUpdater {
.catch(this.emitError.bind(this)); .catch(this.emitError.bind(this));
} }
emitError(error: any) { emitError(error: string | Error) {
if (typeof error === 'string') { if (typeof error === 'string') {
error = new Error(error); error = new Error(error);
} }

View file

@ -7,7 +7,7 @@ import {cfgPath, cfgDir} from './config/paths';
import {getColorMap} from './utils/colors'; import {getColorMap} from './utils/colors';
import {parsedConfig, configOptions} from '../lib/config'; import {parsedConfig, configOptions} from '../lib/config';
const watchers: any[] = []; const watchers: Function[] = [];
let cfg: parsedConfig = {} as any; let cfg: parsedConfig = {} as any;
let _watcher: fs.FSWatcher; let _watcher: fs.FSWatcher;

View file

@ -7,7 +7,7 @@ const NEWS_URL = 'https://hyper-news.now.sh';
export default function fetchNotifications(win: BrowserWindow) { export default function fetchNotifications(win: BrowserWindow) {
const {rpc} = win; const {rpc} = win;
const retry = (err?: any) => { const retry = (err?: Error) => {
setTimeout(() => fetchNotifications(win), ms('30m')); setTimeout(() => fetchNotifications(win), ms('30m'));
if (err) { if (err) {
console.error('Notification messages fetch error', err.stack); console.error('Notification messages fetch error', err.stack);

View file

@ -1,7 +1,7 @@
import {Notification} from 'electron'; import {Notification} from 'electron';
import {icon} from './config/paths'; import {icon} from './config/paths';
export default function notify(title: string, body = '', details: any = {}) { export default function notify(title: string, body = '', details: {error?: any} = {}) {
console.log(`[Notification] ${title}: ${body}`); console.log(`[Notification] ${title}: ${body}`);
if (details.error) { if (details.error) {
console.error(details.error); console.error(details.error);

View file

@ -153,7 +153,7 @@ export default class Session extends EventEmitter {
this.batcher?.write(chunk as any); this.batcher?.write(chunk as any);
}); });
this.batcher.on('flush', (data) => { this.batcher.on('flush', (data: string) => {
this.emit('data', data); this.emit('data', data);
}); });

View file

@ -149,7 +149,7 @@ export function newWindow(
activeUid: options.activeUid activeUid: options.activeUid
}); });
session.on('data', (data: any) => { session.on('data', (data: string) => {
rpc.emit('session data', data); rpc.emit('session data', data);
}); });

View file

@ -86,7 +86,7 @@ const addBinToUserPath = () => {
}); });
}; };
const logNotify = (withNotification: boolean, title: string, body: string, details?: any) => { const logNotify = (withNotification: boolean, title: string, body: string, details?: {error?: any}) => {
console.log(title, body, details); console.log(title, body, details);
withNotification && notify(title, body, details); withNotification && notify(title, body, details);
}; };

View file

@ -1,6 +1,6 @@
// This is a CLI tool, using console is OK // This is a CLI tool, using console is OK
/* eslint no-console: 0 */ /* eslint no-console: 0 */
import {spawn, exec} from 'child_process'; import {spawn, exec, SpawnOptions} from 'child_process';
import {isAbsolute, resolve} from 'path'; import {isAbsolute, resolve} from 'path';
import {existsSync} from 'fs'; import {existsSync} from 'fs';
import {version} from '../app/package.json'; import {version} from '../app/package.json';
@ -42,7 +42,7 @@ args.command(
commandPromise = api commandPromise = api
.install(pluginName) .install(pluginName)
.then(() => console.log(chalk.green(`${pluginName} installed successfully!`))) .then(() => console.log(chalk.green(`${pluginName} installed successfully!`)))
.catch((err: any) => console.error(chalk.red(err))); .catch((err) => console.error(chalk.red(err)));
}, },
['i'] ['i']
); );
@ -202,7 +202,7 @@ const main = (argv: string[]) => {
env['ELECTRON_ENABLE_LOGGING'] = '1'; env['ELECTRON_ENABLE_LOGGING'] = '1';
} }
const options: any = { const options: SpawnOptions = {
detached: true, detached: true,
env env
}; };
@ -231,8 +231,8 @@ const main = (argv: string[]) => {
const child = spawn(process.execPath, args_, options); const child = spawn(process.execPath, args_, options);
if (flags.verbose) { if (flags.verbose) {
child.stdout.on('data', (data) => console.log(data.toString('utf8'))); child.stdout?.on('data', (data) => console.log(data.toString('utf8')));
child.stderr.on('data', (data) => console.error(data.toString('utf8'))); child.stderr?.on('data', (data) => console.error(data.toString('utf8')));
} }
if (flags.verbose) { if (flags.verbose) {
return new Promise((c) => child.once('exit', () => c(null))); return new Promise((c) => child.once('exit', () => c(null)));
@ -247,7 +247,7 @@ function eventuallyExit(code: number) {
main(process.argv) main(process.argv)
.then(() => eventuallyExit(0)) .then(() => eventuallyExit(0))
.catch((err: any) => { .catch((err) => {
console.error(err.stack ? err.stack : err); console.error(err.stack ? err.stack : err);
eventuallyExit(1); eventuallyExit(1);
}); });

View file

@ -50,7 +50,7 @@ export function requestSession() {
}; };
} }
export function addSessionData(uid: string, data: any) { export function addSessionData(uid: string, data: string) {
return (dispatch: HyperDispatch) => { return (dispatch: HyperDispatch) => {
dispatch({ dispatch({
type: SESSION_ADD_DATA, type: SESSION_ADD_DATA,
@ -161,7 +161,7 @@ export function closeSearch(uid?: string, keyEvent?: any) {
}; };
} }
export function sendSessionData(uid: string | null, data: any, escaped?: any) { export function sendSessionData(uid: string | null, data: any, escaped?: boolean | null) {
return (dispatch: HyperDispatch, getState: () => HyperState) => { return (dispatch: HyperDispatch, getState: () => HyperState) => {
dispatch({ dispatch({
type: SESSION_USER_DATA, type: SESSION_USER_DATA,

View file

@ -112,16 +112,15 @@ export function windowGeometryUpdated(): HyperActions {
// Find all sessions that are below the given // Find all sessions that are below the given
// termGroup uid in the hierarchy: // termGroup uid in the hierarchy:
const findChildSessions = (termGroups: any, uid: string): string[] => { const findChildSessions = (termGroups: HyperState['termGroups']['termGroups'], uid: string): string[] => {
const group = termGroups[uid]; const group = termGroups[uid];
if (group.sessionUid) { if (group.sessionUid) {
return [uid]; return [uid];
} }
return group.children.reduce( return group.children
(total: string[], childUid: string) => total.concat(findChildSessions(termGroups, childUid)), .asMutable()
[] .reduce((total: string[], childUid: string) => total.concat(findChildSessions(termGroups, childUid)), []);
);
}; };
// Get the index of the next or previous group, // Get the index of the next or previous group,
@ -318,7 +317,7 @@ export function openSSH(url: string) {
}; };
} }
export function execCommand(command: string, fn: (...args: any[]) => void, e: any) { export function execCommand(command: string, fn: (e: any, dispatch: HyperDispatch) => void, e: any) {
return (dispatch: HyperDispatch) => return (dispatch: HyperDispatch) =>
dispatch({ dispatch({
type: UI_COMMAND_EXEC, type: UI_COMMAND_EXEC,

View file

@ -3,7 +3,7 @@ import {HyperDispatch} from './hyper';
import {closeSearch} from './actions/sessions'; import {closeSearch} from './actions/sessions';
// TODO: Should be updates to new async API https://medium.com/@nornagon/electrons-remote-module-considered-harmful-70d69500f31 // TODO: Should be updates to new async API https://medium.com/@nornagon/electrons-remote-module-considered-harmful-70d69500f31
const {getDecoratedKeymaps} = remote.require('./plugins'); const {getDecoratedKeymaps} = remote.require('./plugins') as typeof import('../app/plugins');
let commands: Record<string, (event: any, dispatch: HyperDispatch) => void> = { let commands: Record<string, (event: any, dispatch: HyperDispatch) => void> = {
'editor:search-close': (e, dispatch) => { 'editor:search-close': (e, dispatch) => {
@ -16,7 +16,7 @@ export const getRegisteredKeys = () => {
return Object.keys(keymaps).reduce((result: Record<string, string>, actionName) => { return Object.keys(keymaps).reduce((result: Record<string, string>, actionName) => {
const commandKeys = keymaps[actionName]; const commandKeys = keymaps[actionName];
commandKeys.forEach((shortcut: string) => { commandKeys.forEach((shortcut) => {
result[shortcut] = actionName; result[shortcut] = actionName;
}); });
return result; return result;

View file

@ -12,13 +12,13 @@ const SplitPane = decorate(SplitPane_, 'SplitPane');
// eslint-disable-next-line @typescript-eslint/class-name-casing // eslint-disable-next-line @typescript-eslint/class-name-casing
class TermGroup_ extends React.PureComponent<TermGroupProps> { class TermGroup_ extends React.PureComponent<TermGroupProps> {
bound: WeakMap<(uid: string, ...args: any[]) => any, Record<string, (...args: any[]) => any>>; bound: WeakMap<(uid: string, ...args: any[]) => any, Record<string, (...args: any[]) => any>>;
term?: Term_; term?: Term_ | null;
constructor(props: TermGroupProps, context: any) { constructor(props: TermGroupProps, context: any) {
super(props, context); super(props, context);
this.bound = new WeakMap(); this.bound = new WeakMap();
} }
bind<T extends (uid: string, ...args: any) => any>( bind<T extends (uid: string, ...args: any[]) => any>(
fn: T, fn: T,
thisObj: any, thisObj: any,
uid: string uid: string
@ -52,7 +52,7 @@ class TermGroup_ extends React.PureComponent<TermGroupProps> {
); );
} }
onTermRef = (uid: string, term: Term_) => { onTermRef = (uid: string, term: Term_ | null) => {
this.term = term; this.term = term;
this.props.ref_(uid, term); this.props.ref_(uid, term);
}; };

View file

@ -3,7 +3,7 @@ import {decorate, getTermGroupProps} from '../utils/plugins';
import {registerCommandHandlers} from '../command-registry'; import {registerCommandHandlers} from '../command-registry';
import TermGroup_ from './term-group'; import TermGroup_ from './term-group';
import StyleSheet_ from './style-sheet'; import StyleSheet_ from './style-sheet';
import {TermsProps} from '../hyper'; import {TermsProps, HyperDispatch} from '../hyper';
import Term from './term'; import Term from './term';
import {ObjectTypedKeys} from '../utils/object'; import {ObjectTypedKeys} from '../utils/object';
@ -14,7 +14,7 @@ const isMac = /Mac/.test(navigator.userAgent);
export default class Terms extends React.Component<TermsProps> { export default class Terms extends React.Component<TermsProps> {
terms: Record<string, Term>; terms: Record<string, Term>;
registerCommands: (cmds: Record<string, (...args: any[]) => void>) => void; registerCommands: (cmds: Record<string, (e: any, dispatch: HyperDispatch) => void>) => void;
constructor(props: TermsProps, context: any) { constructor(props: TermsProps, context: any) {
super(props, context); super(props, context);
this.terms = {}; this.terms = {};
@ -29,7 +29,7 @@ export default class Terms extends React.Component<TermsProps> {
); );
} }
onRef = (uid: string, term: Term) => { onRef = (uid: string, term: Term | null) => {
if (term) { if (term) {
this.terms[uid] = term; this.terms[uid] = term;
} }

View file

@ -10,12 +10,13 @@ import {HeaderContainer} from './header';
import TermsContainer from './terms'; import TermsContainer from './terms';
import NotificationsContainer from './notifications'; import NotificationsContainer from './notifications';
import {HyperState, HyperProps, HyperDispatch} from '../hyper'; import {HyperState, HyperProps, HyperDispatch} from '../hyper';
import Terms from '../components/terms';
const isMac = /Mac/.test(navigator.userAgent); const isMac = /Mac/.test(navigator.userAgent);
class Hyper extends React.PureComponent<HyperProps> { class Hyper extends React.PureComponent<HyperProps> {
mousetrap!: MousetrapInstance; mousetrap!: MousetrapInstance;
terms: any; terms!: Terms;
constructor(props: HyperProps) { constructor(props: HyperProps) {
super(props); super(props);
} }
@ -35,8 +36,8 @@ class Hyper extends React.PureComponent<HyperProps> {
} }
} }
handleFocusActive = (uid: string) => { handleFocusActive = (uid?: string) => {
const term = this.terms.getTermByUid(uid); const term = uid && this.terms.getTermByUid(uid);
if (term) { if (term) {
term.focus(); term.focus();
} }
@ -81,7 +82,7 @@ class Hyper extends React.PureComponent<HyperProps> {
window.rpc.on('term selectAll', this.handleSelectAll); window.rpc.on('term selectAll', this.handleSelectAll);
} }
onTermsRef = (terms: any) => { onTermsRef = (terms: Terms) => {
this.terms = terms; this.terms = terms;
window.focusActiveTerm = this.handleFocusActive; window.focusActiveTerm = this.handleFocusActive;
}; };
@ -153,7 +154,7 @@ const mapStateToProps = (state: HyperState) => {
const mapDispatchToProps = (dispatch: HyperDispatch) => { const mapDispatchToProps = (dispatch: HyperDispatch) => {
return { return {
execCommand: (command: string, fn: (...args: any[]) => void, e: any) => { execCommand: (command: string, fn: (e: any, dispatch: HyperDispatch) => void, e: any) => {
dispatch(uiActions.execCommand(command, fn, e)); dispatch(uiActions.execCommand(command, fn, e));
} }
}; };

23
lib/hyper.d.ts vendored
View file

@ -1,10 +1,11 @@
import {Immutable} from 'seamless-immutable'; import {Immutable} from 'seamless-immutable';
import Client from './utils/rpc';
declare global { declare global {
interface Window { interface Window {
__rpcId: string; __rpcId: string;
rpc: any; rpc: Client;
focusActiveTerm: any; focusActiveTerm: (uid?: string) => void;
} }
} }
@ -154,6 +155,7 @@ export type hyperPlugin = {
mapNotificationsState: any; mapNotificationsState: any;
mapTermsState: any; mapTermsState: any;
middleware: Middleware; middleware: Middleware;
onRendererUnload: any;
onRendererWindow: any; onRendererWindow: any;
reduceSessions: ISessionReducer; reduceSessions: ISessionReducer;
reduceTermGroups: ITermGroupReducer; reduceTermGroups: ITermGroupReducer;
@ -190,11 +192,12 @@ import configureStore from './store/configure-store';
export type HyperThunkDispatch = ThunkDispatch<HyperState, undefined, HyperActions>; export type HyperThunkDispatch = ThunkDispatch<HyperState, undefined, HyperActions>;
export type HyperDispatch = ReturnType<typeof configureStore>['dispatch']; export type HyperDispatch = ReturnType<typeof configureStore>['dispatch'];
import {ReactChild} from 'react';
type extensionProps = Partial<{ type extensionProps = Partial<{
customChildren: any; customChildren: ReactChild | ReactChild[];
customChildrenBefore: any; customChildrenBefore: ReactChild | ReactChild[];
customCSS: string; customCSS: string;
customInnerChildren: any; customInnerChildren: ReactChild | ReactChild[];
}>; }>;
import {HeaderConnectedProps} from './containers/header'; import {HeaderConnectedProps} from './containers/header';
@ -206,8 +209,9 @@ export type HyperProps = HyperConnectedProps & extensionProps;
import {NotificationsConnectedProps} from './containers/notifications'; import {NotificationsConnectedProps} from './containers/notifications';
export type NotificationsProps = NotificationsConnectedProps & extensionProps; export type NotificationsProps = NotificationsConnectedProps & extensionProps;
import Terms from './components/terms';
import {TermsConnectedProps} from './containers/terms'; import {TermsConnectedProps} from './containers/terms';
export type TermsProps = TermsConnectedProps & extensionProps & {ref_: any}; export type TermsProps = TermsConnectedProps & extensionProps & {ref_: (terms: Terms | null) => void};
export type StyleSheetProps = { export type StyleSheetProps = {
backgroundColor: string; backgroundColor: string;
@ -270,7 +274,7 @@ export type TermGroupOwnProps = {
cursorAccentColor?: string; cursorAccentColor?: string;
fontSmoothing?: string; fontSmoothing?: string;
parentProps: TermsProps; parentProps: TermsProps;
ref_: (uid: string, term: Term) => void; ref_: (uid: string, term: Term | null) => void;
termGroup: Immutable<ITermGroup>; termGroup: Immutable<ITermGroup>;
terms: Record<string, Term | null>; terms: Record<string, Term | null>;
} & Pick< } & Pick<
@ -354,7 +358,7 @@ export type TermProps = {
onActive: () => void; onActive: () => void;
onContextMenu: (selection: any) => void; onContextMenu: (selection: any) => void;
onCursorMove?: (cursorFrame: {x: number; y: number; width: number; height: number; col: number; row: number}) => void; onCursorMove?: (cursorFrame: {x: number; y: number; width: number; height: number; col: number; row: number}) => void;
onData: (data: any) => void; onData: (data: string) => void;
onResize: (cols: number, rows: number) => void; onResize: (cols: number, rows: number) => void;
onTitle: (title: string) => void; onTitle: (title: string) => void;
padding: string; padding: string;
@ -371,6 +375,7 @@ export type TermProps = {
url: string | null; url: string | null;
webGLRenderer: boolean; webGLRenderer: boolean;
webLinksActivationKey: string; webLinksActivationKey: string;
} & extensionProps & {ref_?: any}; ref_: (uid: string, term: Term | null) => void;
} & extensionProps;
export type Assignable<T, U> = {[k in keyof U]: k extends keyof T ? T[k] : U[k]} & Partial<T>; export type Assignable<T, U> = {[k in keyof U]: k extends keyof T ? T[k] : U[k]} & Partial<T>;

View file

@ -76,7 +76,7 @@ rpc.on('session add', (data) => {
store_.dispatch(sessionActions.addSession(data)); store_.dispatch(sessionActions.addSession(data));
}); });
rpc.on('session data', (d) => { rpc.on('session data', (d: string) => {
// the uid is a uuid v4 so it's 36 chars long // the uid is a uuid v4 so it's 36 chars long
const uid = d.slice(0, 36); const uid = d.slice(0, 36);
const data = d.slice(36); const data = d.slice(36);

View file

@ -46,7 +46,7 @@ const setActiveGroup = (state: ImmutableType<ITermState>, action: {uid: string})
}; };
// Reduce existing sizes to fit a new split: // Reduce existing sizes to fit a new split:
const insertRebalance = (oldSizes: ImmutableType<number[]>, index: any) => { const insertRebalance = (oldSizes: ImmutableType<number[]>, index: number) => {
const newSize = 1 / (oldSizes.length + 1); const newSize = 1 / (oldSizes.length + 1);
// We spread out how much each pane should be reduced // We spread out how much each pane should be reduced
// with based on their existing size: // with based on their existing size:
@ -167,7 +167,7 @@ const removeGroup = (state: ImmutableType<ITermState>, uid: string) => {
// it's safe to remove the group. // it's safe to remove the group.
if (group.parentUid && state.termGroups[group.parentUid]) { if (group.parentUid && state.termGroups[group.parentUid]) {
const parent = state.termGroups[group.parentUid]; const parent = state.termGroups[group.parentUid];
const newChildren = parent.children.filter((childUid: any) => childUid !== uid); const newChildren = parent.children.filter((childUid) => childUid !== uid);
if (newChildren.length === 1) { if (newChildren.length === 1) {
// Since we only have one child left, // Since we only have one child left,
// we can merge the parent and child into one group: // we can merge the parent and child into one group:
@ -188,7 +188,7 @@ const removeGroup = (state: ImmutableType<ITermState>, uid: string) => {
.set('activeSessions', state.activeSessions.without(uid)); .set('activeSessions', state.activeSessions.without(uid));
}; };
const resizeGroup = (state: ImmutableType<ITermState>, uid: any, sizes: number[]) => { const resizeGroup = (state: ImmutableType<ITermState>, uid: string, sizes: number[]) => {
// Make sure none of the sizes fall below MIN_SIZE: // Make sure none of the sizes fall below MIN_SIZE:
if (sizes.find((size) => size < MIN_SIZE)) { if (sizes.find((size) => size < MIN_SIZE)) {
return state; return state;

View file

@ -1,5 +1,5 @@
/* eslint no-new:0 */ /* eslint no-new:0 */
export default function notify(title: string, body: string, details: Record<string, any> = {}) { export default function notify(title: string, body: string, details: {error?: any} = {}) {
console.log(`[Notification] ${title}: ${body}`); console.log(`[Notification] ${title}: ${body}`);
if (details.error) { if (details.error) {
console.error(details.error); console.error(details.error);