Improve quality of Typescript types (#10742)

This commit is contained in:
Michael Telatynski 2023-05-05 09:11:14 +01:00 committed by GitHub
parent 542bf68c63
commit a4f0b80692
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
30 changed files with 74 additions and 75 deletions

View file

@ -51,7 +51,7 @@ import { isBulkUnverifiedDeviceReminderSnoozed } from "./utils/device/snoozeBulk
const KEY_BACKUP_POLL_INTERVAL = 5 * 60 * 1000; const KEY_BACKUP_POLL_INTERVAL = 5 * 60 * 1000;
export default class DeviceListener { export default class DeviceListener {
private dispatcherRef: string | null; private dispatcherRef?: string;
// device IDs for which the user has dismissed the verify toast ('Later') // device IDs for which the user has dismissed the verify toast ('Later')
private dismissed = new Set<string>(); private dismissed = new Set<string>();
// has the user dismissed any of the various nag toasts to setup encryption on this device? // has the user dismissed any of the various nag toasts to setup encryption on this device?
@ -119,7 +119,7 @@ export default class DeviceListener {
} }
if (this.dispatcherRef) { if (this.dispatcherRef) {
dis.unregister(this.dispatcherRef); dis.unregister(this.dispatcherRef);
this.dispatcherRef = null; this.dispatcherRef = undefined;
} }
this.dismissed.clear(); this.dismissed.clear();
this.dismissedThisDeviceToast = false; this.dismissedThisDeviceToast = false;

View file

@ -34,8 +34,8 @@ import { abbreviateUrl } from "./utils/UrlUtils";
export class AbortedIdentityActionError extends Error {} export class AbortedIdentityActionError extends Error {}
export default class IdentityAuthClient { export default class IdentityAuthClient {
private accessToken: string; private accessToken: string | null = null;
private tempClient: MatrixClient; private tempClient?: MatrixClient;
private authEnabled = true; private authEnabled = true;
/** /**

View file

@ -139,7 +139,7 @@ class MatrixClientPegClass implements IMatrixClientPeg {
// the credentials used to init the current client object. // the credentials used to init the current client object.
// used if we tear it down & recreate it with a different store // used if we tear it down & recreate it with a different store
private currentClientCreds: IMatrixClientCreds; private currentClientCreds: IMatrixClientCreds | null = null;
public get(): MatrixClient { public get(): MatrixClient {
return this.matrixClient; return this.matrixClient;

View file

@ -42,7 +42,7 @@ interface IProps {
*/ */
export default class NodeAnimator extends React.Component<IProps> { export default class NodeAnimator extends React.Component<IProps> {
private nodes: Record<string, ReactInstance> = {}; private nodes: Record<string, ReactInstance> = {};
private children: { [key: string]: ReactElement }; private children: { [key: string]: ReactElement } = {};
public static defaultProps: Partial<IProps> = { public static defaultProps: Partial<IProps> = {
startStyles: [], startStyles: [],
}; };

View file

@ -66,14 +66,14 @@ export enum RecordingState {
} }
export class VoiceRecording extends EventEmitter implements IDestroyable { export class VoiceRecording extends EventEmitter implements IDestroyable {
private recorder: Recorder; private recorder?: Recorder;
private recorderContext: AudioContext; private recorderContext?: AudioContext;
private recorderSource: MediaStreamAudioSourceNode; private recorderSource?: MediaStreamAudioSourceNode;
private recorderStream: MediaStream; private recorderStream?: MediaStream;
private recorderWorklet: AudioWorkletNode; private recorderWorklet?: AudioWorkletNode;
private recorderProcessor: ScriptProcessorNode; private recorderProcessor?: ScriptProcessorNode;
private recording = false; private recording = false;
private observable: SimpleObservable<IRecordingUpdate>; private observable?: SimpleObservable<IRecordingUpdate>;
private targetMaxLength: number | null = TARGET_MAX_LENGTH; private targetMaxLength: number | null = TARGET_MAX_LENGTH;
public amplitudes: number[] = []; // at each second mark, generated public amplitudes: number[] = []; // at each second mark, generated
private liveWaveform = new FixedRollingArray(RECORDING_PLAYBACK_SAMPLES, 0); private liveWaveform = new FixedRollingArray(RECORDING_PLAYBACK_SAMPLES, 0);
@ -84,7 +84,7 @@ export class VoiceRecording extends EventEmitter implements IDestroyable {
} }
public get durationSeconds(): number { public get durationSeconds(): number {
if (!this.recorder) throw new Error("Duration not available without a recording"); if (!this.recorder || !this.recorderContext) throw new Error("Duration not available without a recording");
return this.recorderContext.currentTime; return this.recorderContext.currentTime;
} }
@ -203,7 +203,7 @@ export class VoiceRecording extends EventEmitter implements IDestroyable {
} }
public get liveData(): SimpleObservable<IRecordingUpdate> { public get liveData(): SimpleObservable<IRecordingUpdate> {
if (!this.recording) throw new Error("No observable when not recording"); if (!this.recording || !this.observable) throw new Error("No observable when not recording");
return this.observable; return this.observable;
} }
@ -221,7 +221,7 @@ export class VoiceRecording extends EventEmitter implements IDestroyable {
private processAudioUpdate = (timeSeconds: number): void => { private processAudioUpdate = (timeSeconds: number): void => {
if (!this.recording) return; if (!this.recording) return;
this.observable.update({ this.observable!.update({
waveform: this.liveWaveform.value.map((v) => clamp(v, 0, 1)), waveform: this.liveWaveform.value.map((v) => clamp(v, 0, 1)),
timeSeconds: timeSeconds, timeSeconds: timeSeconds,
}); });
@ -272,7 +272,7 @@ export class VoiceRecording extends EventEmitter implements IDestroyable {
} }
this.observable = new SimpleObservable<IRecordingUpdate>(); this.observable = new SimpleObservable<IRecordingUpdate>();
await this.makeRecorder(); await this.makeRecorder();
await this.recorder.start(); await this.recorder?.start();
this.recording = true; this.recording = true;
this.emit(RecordingState.Started); this.emit(RecordingState.Started);
} }
@ -284,8 +284,8 @@ export class VoiceRecording extends EventEmitter implements IDestroyable {
} }
// Disconnect the source early to start shutting down resources // Disconnect the source early to start shutting down resources
await this.recorder.stop(); // stop first to flush the last frame await this.recorder!.stop(); // stop first to flush the last frame
this.recorderSource.disconnect(); this.recorderSource!.disconnect();
if (this.recorderWorklet) this.recorderWorklet.disconnect(); if (this.recorderWorklet) this.recorderWorklet.disconnect();
if (this.recorderProcessor) { if (this.recorderProcessor) {
this.recorderProcessor.disconnect(); this.recorderProcessor.disconnect();
@ -294,14 +294,14 @@ export class VoiceRecording extends EventEmitter implements IDestroyable {
// close the context after the recorder so the recorder doesn't try to // close the context after the recorder so the recorder doesn't try to
// connect anything to the context (this would generate a warning) // connect anything to the context (this would generate a warning)
await this.recorderContext.close(); await this.recorderContext!.close();
// Now stop all the media tracks so we can release them back to the user/OS // Now stop all the media tracks so we can release them back to the user/OS
this.recorderStream.getTracks().forEach((t) => t.stop()); this.recorderStream!.getTracks().forEach((t) => t.stop());
// Finally do our post-processing and clean up // Finally do our post-processing and clean up
this.recording = false; this.recording = false;
await this.recorder.close(); await this.recorder!.close();
this.emit(RecordingState.Ended); this.emit(RecordingState.Ended);
}); });
} }
@ -313,6 +313,6 @@ export class VoiceRecording extends EventEmitter implements IDestroyable {
this.onDataAvailable = undefined; this.onDataAvailable = undefined;
Singleflight.forgetAllFor(this); Singleflight.forgetAllFor(this);
// noinspection JSIgnoredPromiseFromCall - not concerned about being called async here // noinspection JSIgnoredPromiseFromCall - not concerned about being called async here
this.observable.close(); this.observable?.close();
} }
} }

View file

@ -36,8 +36,8 @@ export interface IAutocompleteOptions {
} }
export default abstract class AutocompleteProvider { export default abstract class AutocompleteProvider {
public commandRegex: RegExp; public commandRegex?: RegExp;
public forcedCommandRegex: RegExp; public forcedCommandRegex?: RegExp;
protected renderingType: TimelineRenderingType = TimelineRenderingType.Room; protected renderingType: TimelineRenderingType = TimelineRenderingType.Room;

View file

@ -47,7 +47,7 @@ interface IOptions<T extends {}> {
*/ */
export default class QueryMatcher<T extends {}> { export default class QueryMatcher<T extends {}> {
private _options: IOptions<T>; private _options: IOptions<T>;
private _items: Map<string, { object: T; keyWeight: number }[]>; private _items = new Map<string, { object: T; keyWeight: number }[]>();
public constructor(objects: T[], options: IOptions<T> = { keys: [] }) { public constructor(objects: T[], options: IOptions<T> = { keys: [] }) {
this._options = options; this._options = options;

View file

@ -44,7 +44,7 @@ const FORCED_USER_REGEX = /[^/,:; \t\n]\S*/g;
export default class UserProvider extends AutocompleteProvider { export default class UserProvider extends AutocompleteProvider {
public matcher: QueryMatcher<RoomMember>; public matcher: QueryMatcher<RoomMember>;
public users: RoomMember[] | null; public users?: RoomMember[];
public room: Room; public room: Room;
public constructor(room: Room, renderingType?: TimelineRenderingType) { public constructor(room: Room, renderingType?: TimelineRenderingType) {
@ -98,7 +98,7 @@ export default class UserProvider extends AutocompleteProvider {
if (state.roomId !== this.room.roomId) return; if (state.roomId !== this.room.roomId) return;
// blow away the users cache // blow away the users cache
this.users = null; this.users = undefined;
}; };
public async getCompletions( public async getCompletions(

View file

@ -67,9 +67,9 @@ const enum LoginField {
* The email/username/phone fields are fully-controlled, the password field is not. * The email/username/phone fields are fully-controlled, the password field is not.
*/ */
export default class PasswordLogin extends React.PureComponent<IProps, IState> { export default class PasswordLogin extends React.PureComponent<IProps, IState> {
private [LoginField.Email]: Field | null; private [LoginField.Email]: Field | null = null;
private [LoginField.Phone]: Field | null; private [LoginField.Phone]: Field | null = null;
private [LoginField.MatrixId]: Field | null; private [LoginField.MatrixId]: Field | null = null;
public static defaultProps = { public static defaultProps = {
onUsernameChanged: function () {}, onUsernameChanged: function () {},

View file

@ -95,11 +95,11 @@ interface IState {
* A pure UI component which displays a registration form. * A pure UI component which displays a registration form.
*/ */
export default class RegistrationForm extends React.PureComponent<IProps, IState> { export default class RegistrationForm extends React.PureComponent<IProps, IState> {
private [RegistrationField.Email]: Field | null; private [RegistrationField.Email]: Field | null = null;
private [RegistrationField.Password]: Field | null; private [RegistrationField.Password]: Field | null = null;
private [RegistrationField.PasswordConfirm]: Field | null; private [RegistrationField.PasswordConfirm]: Field | null = null;
private [RegistrationField.Username]: Field | null; private [RegistrationField.Username]: Field | null = null;
private [RegistrationField.PhoneNumber]: Field | null; private [RegistrationField.PhoneNumber]: Field | null = null;
public static defaultProps = { public static defaultProps = {
onValidationChange: logger.error, onValidationChange: logger.error,

View file

@ -78,7 +78,7 @@ function tooltipText(variant: Icon): string | undefined {
} }
export default class DecoratedRoomAvatar extends React.PureComponent<IProps, IState> { export default class DecoratedRoomAvatar extends React.PureComponent<IProps, IState> {
private _dmUser: User | null; private _dmUser: User | null = null;
private isUnmounted = false; private isUnmounted = false;
private isWatchingTimeline = false; private isWatchingTimeline = false;

View file

@ -50,9 +50,9 @@ interface IState {
} }
export default class Autocomplete extends React.PureComponent<IProps, IState> { export default class Autocomplete extends React.PureComponent<IProps, IState> {
public autocompleter: Autocompleter; public autocompleter?: Autocompleter;
public queryRequested: string; public queryRequested?: string;
public debounceCompletionsRequest: number; public debounceCompletionsRequest?: number;
private containerRef = createRef<HTMLDivElement>(); private containerRef = createRef<HTMLDivElement>();
public static contextType = RoomContext; public static contextType = RoomContext;
@ -86,7 +86,7 @@ export default class Autocomplete extends React.PureComponent<IProps, IState> {
private applyNewProps(oldQuery?: string, oldRoom?: Room): void { private applyNewProps(oldQuery?: string, oldRoom?: Room): void {
if (oldRoom && this.props.room.roomId !== oldRoom.roomId) { if (oldRoom && this.props.room.roomId !== oldRoom.roomId) {
this.autocompleter.destroy(); this.autocompleter?.destroy();
this.autocompleter = new Autocompleter(this.props.room); this.autocompleter = new Autocompleter(this.props.room);
} }
@ -99,7 +99,7 @@ export default class Autocomplete extends React.PureComponent<IProps, IState> {
} }
public componentWillUnmount(): void { public componentWillUnmount(): void {
this.autocompleter.destroy(); this.autocompleter?.destroy();
} }
private complete(query: string, selection: ISelectionRange): Promise<void> { private complete(query: string, selection: ISelectionRange): Promise<void> {

View file

@ -132,7 +132,7 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
private _isCaretAtEnd: boolean; private _isCaretAtEnd: boolean;
private lastCaret: DocumentOffset; private lastCaret: DocumentOffset;
private lastSelection: ReturnType<typeof cloneSelection> | null; private lastSelection: ReturnType<typeof cloneSelection> | null = null;
private readonly useMarkdownHandle: string; private readonly useMarkdownHandle: string;
private readonly emoticonSettingHandle: string; private readonly emoticonSettingHandle: string;

View file

@ -64,9 +64,9 @@ export default class Stickerpicker extends React.PureComponent<IProps, IState> {
public static currentWidget?: IWidgetEvent; public static currentWidget?: IWidgetEvent;
private dispatcherRef: string; private dispatcherRef?: string;
private prevSentVisibility: boolean; private prevSentVisibility?: boolean;
private popoverWidth = 300; private popoverWidth = 300;
private popoverHeight = 300; private popoverHeight = 300;

View file

@ -49,7 +49,7 @@ interface IState extends IThemeState {
} }
export default class ThemeChoicePanel extends React.Component<IProps, IState> { export default class ThemeChoicePanel extends React.Component<IProps, IState> {
private themeTimer: number; private themeTimer?: number;
public constructor(props: IProps) { public constructor(props: IProps) {
super(props); super(props);

View file

@ -87,7 +87,7 @@ interface IState {
} }
export default class SecurityUserSettingsTab extends React.Component<IProps, IState> { export default class SecurityUserSettingsTab extends React.Component<IProps, IState> {
private dispatcherRef: string; private dispatcherRef?: string;
public constructor(props: IProps) { public constructor(props: IProps) {
super(props); super(props);
@ -124,7 +124,7 @@ export default class SecurityUserSettingsTab extends React.Component<IProps, ISt
} }
public componentWillUnmount(): void { public componentWillUnmount(): void {
dis.unregister(this.dispatcherRef); if (this.dispatcherRef) dis.unregister(this.dispatcherRef);
MatrixClientPeg.get().removeListener(RoomEvent.MyMembership, this.onMyMembership); MatrixClientPeg.get().removeListener(RoomEvent.MyMembership, this.onMyMembership);
} }

View file

@ -47,7 +47,7 @@ interface IState {
} }
export default class VerificationRequestToast extends React.PureComponent<IProps, IState> { export default class VerificationRequestToast extends React.PureComponent<IProps, IState> {
private intervalHandle: number; private intervalHandle?: number;
public constructor(props: IProps) { public constructor(props: IProps) {
super(props); super(props);

View file

@ -100,7 +100,7 @@ function exitFullscreen(): void {
} }
export default class LegacyCallView extends React.Component<IProps, IState> { export default class LegacyCallView extends React.Component<IProps, IState> {
private dispatcherRef: string; private dispatcherRef?: string;
private contentWrapperRef = createRef<HTMLDivElement>(); private contentWrapperRef = createRef<HTMLDivElement>();
private buttonsRef = createRef<LegacyCallViewButtons>(); private buttonsRef = createRef<LegacyCallViewButtons>();
@ -137,7 +137,7 @@ export default class LegacyCallView extends React.Component<IProps, IState> {
document.removeEventListener("keydown", this.onNativeKeyDown); document.removeEventListener("keydown", this.onNativeKeyDown);
this.updateCallListeners(this.props.call, null); this.updateCallListeners(this.props.call, null);
dis.unregister(this.dispatcherRef); if (this.dispatcherRef) dis.unregister(this.dispatcherRef);
} }
public static getDerivedStateFromProps(props: IProps): Partial<IState> { public static getDerivedStateFromProps(props: IProps): Partial<IState> {

View file

@ -52,7 +52,7 @@ interface IState {
} }
export default class VideoFeed extends React.PureComponent<IProps, IState> { export default class VideoFeed extends React.PureComponent<IProps, IState> {
private element: HTMLVideoElement; private element?: HTMLVideoElement;
public constructor(props: IProps) { public constructor(props: IProps) {
super(props); super(props);

View file

@ -32,7 +32,7 @@ export type GetAutocompleterComponent = () => Autocomplete | null;
export type UpdateQuery = (test: string) => Promise<void>; export type UpdateQuery = (test: string) => Promise<void>;
export default class AutocompleteWrapperModel { export default class AutocompleteWrapperModel {
private partIndex: number; private partIndex?: number;
public constructor( public constructor(
private updateCallback: UpdateCallback, private updateCallback: UpdateCallback,

View file

@ -39,8 +39,8 @@ export class IntegrationManagers {
private static instance?: IntegrationManagers; private static instance?: IntegrationManagers;
private managers: IntegrationManagerInstance[] = []; private managers: IntegrationManagerInstance[] = [];
private client: MatrixClient; private client?: MatrixClient;
private primaryManager: IntegrationManagerInstance | null; private primaryManager: IntegrationManagerInstance | null = null;
public static sharedInstance(): IntegrationManagers { public static sharedInstance(): IntegrationManagers {
if (!IntegrationManagers.instance) { if (!IntegrationManagers.instance) {

View file

@ -35,7 +35,7 @@ export class LocalRoom extends Room {
/** Whether the actual room should be encrypted. */ /** Whether the actual room should be encrypted. */
public encrypted = false; public encrypted = false;
/** If the actual room has been created, this holds its ID. */ /** If the actual room has been created, this holds its ID. */
public actualRoomId: string; public actualRoomId?: string;
/** DM chat partner */ /** DM chat partner */
public targets: Member[] = []; public targets: Member[] = [];
/** Callbacks that should be invoked after the actual room has been created. */ /** Callbacks that should be invoked after the actual room has been created. */

View file

@ -20,7 +20,7 @@ import { IEncryptedFile } from "../customisations/models/IMediaEventContent";
export class RoomUpload { export class RoomUpload {
public readonly abortController = new AbortController(); public readonly abortController = new AbortController();
public promise: Promise<{ url?: string; file?: IEncryptedFile }>; public promise?: Promise<{ url?: string; file?: IEncryptedFile }>;
private uploaded = 0; private uploaded = 0;
public constructor( public constructor(

View file

@ -39,8 +39,8 @@ export enum ActiveWidgetStoreEvent {
*/ */
export default class ActiveWidgetStore extends EventEmitter { export default class ActiveWidgetStore extends EventEmitter {
private static internalInstance: ActiveWidgetStore; private static internalInstance: ActiveWidgetStore;
private persistentWidgetId: string | null; private persistentWidgetId: string | null = null;
private persistentRoomId: string | null; private persistentRoomId: string | null = null;
private dockedWidgetsByUid = new Map<string, number>(); private dockedWidgetsByUid = new Map<string, number>();
public static get instance(): ActiveWidgetStore { public static get instance(): ActiveWidgetStore {

View file

@ -43,7 +43,7 @@ export class OwnProfileStore extends AsyncStoreWithClient<IState> {
return instance; return instance;
})(); })();
private monitoredUser: User | null; private monitoredUser: User | null = null;
private constructor() { private constructor() {
// seed from localstorage because otherwise we won't get these values until a whole network // seed from localstorage because otherwise we won't get these values until a whole network

View file

@ -28,7 +28,7 @@ export const PROPERTY_UPDATED = "property_updated";
export abstract class GenericEchoChamber<C extends EchoContext, K, V> extends EventEmitter { export abstract class GenericEchoChamber<C extends EchoContext, K, V> extends EventEmitter {
private cache = new Map<K, { txn: EchoTransaction; val: V }>(); private cache = new Map<K, { txn: EchoTransaction; val: V }>();
protected matrixClient: MatrixClient | null; protected matrixClient: MatrixClient | null = null;
protected constructor(public readonly context: C, private lookupFn: (key: K) => V) { protected constructor(public readonly context: C, private lookupFn: (key: K) => V) {
super(); super();

View file

@ -18,8 +18,8 @@ limitations under the License.
* Utility class for lazily getting a variable. * Utility class for lazily getting a variable.
*/ */
export class LazyValue<T> { export class LazyValue<T> {
private val: T; private val?: T;
private prom: Promise<T>; private prom?: Promise<T>;
private done = false; private done = false;
public constructor(private getFn: () => Promise<T>) {} public constructor(private getFn: () => Promise<T>) {}
@ -36,7 +36,7 @@ export class LazyValue<T> {
* Gets the value without invoking a get. May be undefined until the * Gets the value without invoking a get. May be undefined until the
* value is fetched properly. * value is fetched properly.
*/ */
public get cachedValue(): T { public get cachedValue(): T | undefined {
return this.val; return this.val;
} }

View file

@ -14,16 +14,16 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
export class ValidatedServerConfig { export interface ValidatedServerConfig {
public hsUrl: string; hsUrl: string;
public hsName: string; hsName: string;
public hsNameIsDifferent: boolean; hsNameIsDifferent: boolean;
public isUrl: string; isUrl: string;
public isDefault: boolean; isDefault: boolean;
// when the server config is based on static URLs the hsName is not resolvable and things may wish to use hsUrl // when the server config is based on static URLs the hsName is not resolvable and things may wish to use hsUrl
public isNameResolvable: boolean; isNameResolvable: boolean;
public warning: string | Error; warning: string | Error;
} }

View file

@ -31,7 +31,7 @@ export interface JitsiWidgetData {
export class Jitsi { export class Jitsi {
private static instance: Jitsi; private static instance: Jitsi;
private domain: string; private domain?: string;
public get preferredDomain(): string { public get preferredDomain(): string {
return this.domain || "meet.element.io"; return this.domain || "meet.element.io";

View file

@ -76,8 +76,7 @@ describe("<ForgotPassword>", () => {
client = stubClient(); client = stubClient();
mocked(createClient).mockReturnValue(client); mocked(createClient).mockReturnValue(client);
serverConfig = new ValidatedServerConfig(); serverConfig = { hsName: "example.com" } as ValidatedServerConfig;
serverConfig.hsName = "example.com";
onComplete = jest.fn(); onComplete = jest.fn();
onLoginClick = jest.fn(); onLoginClick = jest.fn();