1
0
mirror of https://github.com/flarum/core.git synced 2025-07-27 11:40:24 +02:00

Various TypeScript improvements (#2309)

- Use Mithril.Attributes as base for ComponentAttrs, remove =any from class signature for Component
- Convert Alert to TypeScript, introduce AlertAttrs interface
- Convert AlertManagerState to TypeScript, add overload signatures for `show`, introduce AlertState interface for stored Alerts.
- Set ComponentAttrs as default T for Component
- Make attrs in AlertAttrs optional
- Add AlertIdentifier interface, simplify show type signature
- Remove mithril patch shim, as all patches onto m are now deprecated
- Use Mithril.Static for shim
This commit is contained in:
Alexander Skvortsov
2020-10-02 18:49:40 -04:00
committed by GitHub
parent dc4884485a
commit d695d96e00
4 changed files with 53 additions and 47 deletions

12
js/shims.d.ts vendored
View File

@@ -1,6 +1,5 @@
// Mithril // Mithril
import * as Mithril from 'mithril'; import Mithril from 'mithril';
import Stream from 'mithril/stream';
// Other third-party libs // Other third-party libs
import * as _dayjs from 'dayjs'; import * as _dayjs from 'dayjs';
@@ -9,13 +8,6 @@ import * as _$ from 'jquery';
// Globals from flarum/core // Globals from flarum/core
import Application from './src/common/Application'; import Application from './src/common/Application';
/**
* Helpers that flarum/core patches into Mithril
*/
interface m extends Mithril.Static {
prop: typeof Stream;
}
/** /**
* Export Mithril typings globally. * Export Mithril typings globally.
* *
@@ -36,7 +28,7 @@ export as namespace Mithril;
*/ */
declare global { declare global {
const $: typeof _$; const $: typeof _$;
const m: m; const m: Mithril.Static;
const dayjs: typeof _dayjs; const dayjs: typeof _dayjs;
} }

View File

@@ -3,11 +3,7 @@ import * as Mithril from 'mithril';
let deprecatedPropsWarned = false; let deprecatedPropsWarned = false;
let deprecatedInitPropsWarned = false; let deprecatedInitPropsWarned = false;
export type ComponentAttrs = { export interface ComponentAttrs extends Mithril.Attributes {}
className?: string;
[key: string]: any;
};
/** /**
* The `Component` class defines a user interface 'building block'. A component * The `Component` class defines a user interface 'building block'. A component
@@ -36,7 +32,7 @@ export type ComponentAttrs = {
* *
* @see https://mithril.js.org/components.html * @see https://mithril.js.org/components.html
*/ */
export default abstract class Component<T extends ComponentAttrs = any> implements Mithril.ClassComponent<T> { export default abstract class Component<T extends ComponentAttrs = ComponentAttrs> implements Mithril.ClassComponent<T> {
/** /**
* The root DOM element for the component. * The root DOM element for the component.
*/ */

View File

@@ -1,31 +1,33 @@
import Component from '../Component'; import Component, { ComponentAttrs } from '../Component';
import Button from './Button'; import Button from './Button';
import listItems from '../helpers/listItems'; import listItems from '../helpers/listItems';
import extract from '../utils/extract'; import extract from '../utils/extract';
import Mithril from 'mithril';
export interface AlertAttrs extends ComponentAttrs {
/** The type of alert this is. Will be used to give the alert a class name of `Alert--{type}`. */
type?: string;
/** An array of controls to show in the alert. */
controls?: Mithril.Children;
/** Whether or not the alert can be dismissed. */
dismissible?: boolean;
/** A callback to run when the alert is dismissed */
ondismiss?: Function;
}
/** /**
* The `Alert` component represents an alert box, which contains a message, * The `Alert` component represents an alert box, which contains a message,
* some controls, and may be dismissible. * some controls, and may be dismissible.
*
* ### Attrs
*
* - `type` The type of alert this is. Will be used to give the alert a class
* name of `Alert--{type}`.
* - `controls` An array of controls to show in the alert.
* - `dismissible` Whether or not the alert can be dismissed.
* - `ondismiss` A callback to run when the alert is dismissed.
*
* All other attrs will be assigned as attributes on the DOM element.
*/ */
export default class Alert extends Component { export default class Alert<T extends AlertAttrs = AlertAttrs> extends Component<T> {
view(vnode) { view(vnode: Mithril.Vnode) {
const attrs = Object.assign({}, this.attrs); const attrs = Object.assign({}, this.attrs);
const type = extract(attrs, 'type'); const type = extract(attrs, 'type');
attrs.className = 'Alert Alert--' + type + ' ' + (attrs.className || ''); attrs.className = 'Alert Alert--' + type + ' ' + (attrs.className || '');
const content = extract(attrs, 'content') || vnode.children; const content = extract(attrs, 'content') || vnode.children;
const controls = extract(attrs, 'controls') || []; const controls = (extract(attrs, 'controls') || []) as Mithril.ChildArray;
// If the alert is meant to be dismissible (which is the case by default), // If the alert is meant to be dismissible (which is the case by default),
// then we will create a dismiss button to append as the final control in // then we will create a dismiss button to append as the final control in

View File

@@ -1,10 +1,20 @@
import Alert from '../components/Alert'; import Mithril from 'mithril';
import Alert, { AlertAttrs } from '../components/Alert';
/**
* Returned by `AlertManagerState.show`. Used to dismiss alerts.
*/
export type AlertIdentifier = number;
export interface AlertState {
componentClass: typeof Alert;
attrs: AlertAttrs;
children: Mithril.Children;
}
export default class AlertManagerState { export default class AlertManagerState {
constructor() { protected activeAlerts: { [id: number]: AlertState } = {};
this.activeAlerts = {}; protected alertId = 0;
this.alertId = 0;
}
getActiveAlerts() { getActiveAlerts() {
return this.activeAlerts; return this.activeAlerts;
@@ -12,19 +22,27 @@ export default class AlertManagerState {
/** /**
* Show an Alert in the alerts area. * Show an Alert in the alerts area.
*
* @returns The alert's ID, which can be used to dismiss the alert.
*/ */
show(arg1, arg2, arg3) { show(children: Mithril.Children): AlertIdentifier;
show(attrs: AlertAttrs, children: Mithril.Children): AlertIdentifier;
show(componentClass: Alert, attrs: AlertAttrs, children: Mithril.Children): AlertIdentifier;
show(arg1: any, arg2?: any, arg3?: any) {
// Assigns variables as per the above signatures
let componentClass = Alert; let componentClass = Alert;
let attrs = {}; let attrs: AlertAttrs = {};
let children; let children: Mithril.Children;
if (arguments.length == 1) { if (arguments.length == 1) {
children = arg1; children = arg1 as Mithril.Children;
} else if (arguments.length == 2) { } else if (arguments.length == 2) {
attrs = arg1; attrs = arg1 as AlertAttrs;
children = arg2; children = arg2 as Mithril.Children;
} else if (arguments.length == 3) { } else if (arguments.length == 3) {
componentClass = arg1; componentClass = arg1 as typeof Alert;
attrs = arg2; attrs = arg2 as AlertAttrs;
children = arg3; children = arg3;
} }
@@ -45,7 +63,7 @@ export default class AlertManagerState {
/** /**
* Dismiss an alert. * Dismiss an alert.
*/ */
dismiss(key) { dismiss(key: AlertIdentifier): void {
if (!key || !(key in this.activeAlerts)) return; if (!key || !(key in this.activeAlerts)) return;
delete this.activeAlerts[key]; delete this.activeAlerts[key];
@@ -54,10 +72,8 @@ export default class AlertManagerState {
/** /**
* Clear all alerts. * Clear all alerts.
*
* @public
*/ */
clear() { clear(): void {
this.activeAlerts = {}; this.activeAlerts = {};
m.redraw(); m.redraw();
} }