Apply more strict typescript around the codebase (#2778)

* Apply more strict typescript around the codebase

* Fix tests

* Revert strict mode commit

* Iterate strict

* Iterate

* Iterate strict

* Iterate

* Fix tests

* Iterate

* Iterate strict

* Add tests

* Iterate

* Iterate

* Fix tests

* Fix tests

* Strict types be strict

* Fix types

* detectOpenHandles

* Strict

* Fix client not stopping

* Add sync peeking tests

* Make test happier

* More strict

* Iterate

* Stabilise

* Moar strictness

* Improve coverage

* Fix types

* Fix types

* Improve types further

* Fix types

* Improve typing of NamespacedValue

* Fix types
This commit is contained in:
Michael Telatynski
2022-10-21 11:44:40 +01:00
committed by GitHub
parent fdbbd9bca4
commit 867a0ca7ee
94 changed files with 1980 additions and 1735 deletions
+2 -2
View File
@@ -86,7 +86,7 @@ export class MSC3089TreeSpace {
public readonly room: Room;
public constructor(private client: MatrixClient, public readonly roomId: string) {
this.room = this.client.getRoom(this.roomId);
this.room = this.client.getRoom(this.roomId)!;
if (!this.room) throw new Error("Unknown room");
}
@@ -282,7 +282,7 @@ export class MSC3089TreeSpace {
const members = this.room.currentState.getStateEvents(EventType.RoomMember);
for (const member of members) {
const isNotUs = member.getStateKey() !== this.client.getUserId();
if (isNotUs && kickMemberships.includes(member.getContent().membership)) {
if (isNotUs && kickMemberships.includes(member.getContent().membership!)) {
const stateKey = member.getStateKey();
if (!stateKey) {
throw new Error("State key not found for branch");
+21 -19
View File
@@ -51,21 +51,21 @@ export const getBeaconInfoIdentifier = (event: MatrixEvent): BeaconIdentifier =>
// https://github.com/matrix-org/matrix-spec-proposals/pull/3672
export class Beacon extends TypedEventEmitter<Exclude<BeaconEvent, BeaconEvent.New>, BeaconEventHandlerMap> {
public readonly roomId: string;
private _beaconInfo: BeaconInfoState;
private _isLive: boolean;
private livenessWatchTimeout: ReturnType<typeof setTimeout>;
private _latestLocationEvent: MatrixEvent | undefined;
private _beaconInfo?: BeaconInfoState;
private _isLive?: boolean;
private livenessWatchTimeout?: ReturnType<typeof setTimeout>;
private _latestLocationEvent?: MatrixEvent;
constructor(
private rootEvent: MatrixEvent,
) {
super();
this.setBeaconInfo(this.rootEvent);
this.roomId = this.rootEvent.getRoomId();
this.roomId = this.rootEvent.getRoomId()!;
}
public get isLive(): boolean {
return this._isLive;
return !!this._isLive;
}
public get identifier(): BeaconIdentifier {
@@ -77,14 +77,14 @@ export class Beacon extends TypedEventEmitter<Exclude<BeaconEvent, BeaconEvent.N
}
public get beaconInfoOwner(): string {
return this.rootEvent.getStateKey();
return this.rootEvent.getStateKey()!;
}
public get beaconInfoEventType(): string {
return this.rootEvent.getType();
}
public get beaconInfo(): BeaconInfoState {
public get beaconInfo(): BeaconInfoState | undefined {
return this._beaconInfo;
}
@@ -101,7 +101,7 @@ export class Beacon extends TypedEventEmitter<Exclude<BeaconEvent, BeaconEvent.N
throw new Error('Invalid updating event');
}
// don't update beacon with an older event
if (beaconInfoEvent.event.origin_server_ts < this.rootEvent.event.origin_server_ts) {
if (beaconInfoEvent.getTs() < this.rootEvent.getTs()) {
return;
}
this.rootEvent = beaconInfoEvent;
@@ -130,20 +130,21 @@ export class Beacon extends TypedEventEmitter<Exclude<BeaconEvent, BeaconEvent.N
}
this.checkLiveness();
if (!this.beaconInfo) return;
if (this.isLive) {
const expiryInMs = (this._beaconInfo?.timestamp + this._beaconInfo?.timeout) - Date.now();
const expiryInMs = (this.beaconInfo.timestamp + this.beaconInfo.timeout) - Date.now();
if (expiryInMs > 1) {
this.livenessWatchTimeout = setTimeout(
() => { this.monitorLiveness(); },
expiryInMs,
);
}
} else if (this._beaconInfo?.timestamp > Date.now()) {
} else if (this.beaconInfo.timestamp > Date.now()) {
// beacon start timestamp is in the future
// check liveness again then
this.livenessWatchTimeout = setTimeout(
() => { this.monitorLiveness(); },
this.beaconInfo?.timestamp - Date.now(),
this.beaconInfo.timestamp - Date.now(),
);
}
}
@@ -165,22 +166,22 @@ export class Beacon extends TypedEventEmitter<Exclude<BeaconEvent, BeaconEvent.N
const { timestamp } = parsed;
return (
// only include positions that were taken inside the beacon's live period
isTimestampInDuration(this._beaconInfo.timestamp, this._beaconInfo.timeout, timestamp) &&
isTimestampInDuration(this._beaconInfo!.timestamp, this._beaconInfo!.timeout, timestamp) &&
// ignore positions older than our current latest location
(!this.latestLocationState || timestamp > this.latestLocationState.timestamp)
(!this.latestLocationState || timestamp > this.latestLocationState.timestamp!)
);
});
const latestLocationEvent = validLocationEvents.sort(sortEventsByLatestContentTimestamp)?.[0];
if (latestLocationEvent) {
this._latestLocationEvent = latestLocationEvent;
this.emit(BeaconEvent.LocationUpdate, this.latestLocationState);
this.emit(BeaconEvent.LocationUpdate, this.latestLocationState!);
}
}
private clearLatestLocation = () => {
this._latestLocationEvent = undefined;
this.emit(BeaconEvent.LocationUpdate, this.latestLocationState);
this.emit(BeaconEvent.LocationUpdate, this.latestLocationState!);
};
private setBeaconInfo(event: MatrixEvent): void {
@@ -195,9 +196,10 @@ export class Beacon extends TypedEventEmitter<Exclude<BeaconEvent, BeaconEvent.N
// when Alice's system clock deviates slightly from Bob's a beacon Alice intended to be live
// may have a start timestamp in the future from Bob's POV
// handle this by adding 6min of leniency to the start timestamp when it is in the future
const startTimestamp = this._beaconInfo?.timestamp > Date.now() ?
this._beaconInfo?.timestamp - 360000 /* 6min */ :
this._beaconInfo?.timestamp;
if (!this.beaconInfo) return;
const startTimestamp = this.beaconInfo.timestamp > Date.now() ?
this.beaconInfo.timestamp - 360000 /* 6min */ :
this.beaconInfo.timestamp;
this._isLive = !!this._beaconInfo?.live &&
isTimestampInDuration(startTimestamp, this._beaconInfo?.timeout, Date.now());
+1 -1
View File
@@ -822,7 +822,7 @@ export class EventTimelineSet extends TypedEventEmitter<EmittedEvents, EventTime
// linkedlist to see which comes first.
// first work forwards from timeline1
let tl = timeline1;
let tl: EventTimeline | null = timeline1;
while (tl) {
if (tl === timeline2) {
// timeline1 is before timeline2
+7 -10
View File
@@ -77,7 +77,7 @@ export class EventTimeline {
event.sender = stateContext.getSentinelMember(event.getSender());
}
if (!event.target?.events?.member && event.getType() === EventType.RoomMember) {
event.target = stateContext.getSentinelMember(event.getStateKey());
event.target = stateContext.getSentinelMember(event.getStateKey()!);
}
if (event.isState()) {
@@ -97,8 +97,8 @@ export class EventTimeline {
private baseIndex = 0;
private startState: RoomState;
private endState: RoomState;
private prevTimeline?: EventTimeline;
private nextTimeline?: EventTimeline;
private prevTimeline: EventTimeline | null = null;
private nextTimeline: EventTimeline | null = null;
public paginationRequests: Record<Direction, Promise<boolean> | null> = {
[Direction.Backward]: null,
[Direction.Forward]: null,
@@ -131,9 +131,6 @@ export class EventTimeline {
this.endState = new RoomState(this.roomId);
this.endState.paginationToken = null;
this.prevTimeline = null;
this.nextTimeline = null;
// this is used by client.js
this.paginationRequests = { 'b': null, 'f': null };
@@ -226,7 +223,7 @@ export class EventTimeline {
* Get the ID of the room for this timeline
* @return {string} room ID
*/
public getRoomId(): string {
public getRoomId(): string | null {
return this.roomId;
}
@@ -234,7 +231,7 @@ export class EventTimeline {
* Get the filter for this timeline's timelineSet (if any)
* @return {Filter} filter
*/
public getFilter(): Filter {
public getFilter(): Filter | undefined {
return this.eventTimelineSet.getFilter();
}
@@ -324,7 +321,7 @@ export class EventTimeline {
* @return {?EventTimeline} previous or following timeline, if they have been
* joined up.
*/
public getNeighbouringTimeline(direction: Direction): EventTimeline {
public getNeighbouringTimeline(direction: Direction): EventTimeline | null {
if (direction == EventTimeline.BACKWARDS) {
return this.prevTimeline;
} else if (direction == EventTimeline.FORWARDS) {
@@ -391,7 +388,7 @@ export class EventTimeline {
roomState?: RoomState,
): void {
let toStartOfTimeline = !!toStartOfTimelineOrOpts;
let timelineWasEmpty: boolean;
let timelineWasEmpty: boolean | undefined;
if (typeof (toStartOfTimelineOrOpts) === 'object') {
({ toStartOfTimeline, roomState, timelineWasEmpty } = toStartOfTimelineOrOpts);
} else if (toStartOfTimelineOrOpts !== undefined) {
+8 -11
View File
@@ -34,6 +34,7 @@ import { TypedReEmitter } from '../ReEmitter';
import { MatrixError } from "../http-api";
import { TypedEventEmitter } from "./typed-event-emitter";
import { EventStatus } from "./event-status";
import { DecryptionError } from "../crypto/algorithms";
export { EventStatus } from "./event-status";
@@ -685,14 +686,6 @@ export class MatrixEvent extends TypedEventEmitter<MatrixEventEmittedEvents, Mat
* attempt is completed.
*/
public async attemptDecryption(crypto: Crypto, options: IDecryptOptions = {}): Promise<void> {
// For backwards compatibility purposes
// The function signature used to be attemptDecryption(crypto, isRetry)
if (typeof options === "boolean") {
options = {
isRetry: options,
};
}
// start with a couple of sanity checks.
if (!this.isEncrypted()) {
throw new Error("Attempt to decrypt event which isn't encrypted");
@@ -822,15 +815,19 @@ export class MatrixEvent extends TypedEventEmitter<MatrixEventEmittedEvents, Mat
//
if (this.retryDecryption) {
// decryption error, but we have a retry queued.
logger.log(`Got error decrypting event (id=${this.getId()}: ${e.detailedString}), but retrying`, e);
logger.log(`Got error decrypting event (id=${this.getId()}: ` +
`${(<DecryptionError>e).detailedString}), but retrying`, e);
continue;
}
// decryption error, no retries queued. Warn about the error and
// set it to m.bad.encrypted.
logger.warn(`Got error decrypting event (id=${this.getId()}: ${e.detailedString})`, e);
logger.warn(
`Got error decrypting event (id=${this.getId()}: ${(<DecryptionError>e).detailedString})`,
e,
);
res = this.badEncryptedMessage(e.message);
res = this.badEncryptedMessage((<DecryptionError>e).message);
}
// at this point, we've either successfully decrypted the event, or have given up
+8 -8
View File
@@ -118,31 +118,31 @@ export class RelationsContainer {
const { event_id: relatesToEventId, rel_type: relationType } = relation;
const eventType = event.getType();
let relationsForEvent = this.relations.get(relatesToEventId);
let relationsForEvent = this.relations.get(relatesToEventId!);
if (!relationsForEvent) {
relationsForEvent = new Map<RelationType | string, Map<EventType | string, Relations>>();
this.relations.set(relatesToEventId, relationsForEvent);
this.relations.set(relatesToEventId!, relationsForEvent);
}
let relationsWithRelType = relationsForEvent.get(relationType);
let relationsWithRelType = relationsForEvent.get(relationType!);
if (!relationsWithRelType) {
relationsWithRelType = new Map<EventType | string, Relations>();
relationsForEvent.set(relationType, relationsWithRelType);
relationsForEvent.set(relationType!, relationsWithRelType);
}
let relationsWithEventType = relationsWithRelType.get(eventType);
if (!relationsWithEventType) {
relationsWithEventType = new Relations(
relationType,
relationType!,
eventType,
this.client,
);
relationsWithRelType.set(eventType, relationsWithEventType);
const room = this.room ?? timelineSet?.room;
const relatesToEvent = timelineSet?.findEventById(relatesToEventId)
?? room?.findEventById(relatesToEventId)
?? room?.getPendingEvent(relatesToEventId);
const relatesToEvent = timelineSet?.findEventById(relatesToEventId!)
?? room?.findEventById(relatesToEventId!)
?? room?.getPendingEvent(relatesToEventId!);
if (relatesToEvent) {
relationsWithEventType.setTargetEvent(relatesToEvent);
}
+14 -18
View File
@@ -47,7 +47,7 @@ export class Relations extends TypedEventEmitter<RelationsEvent, EventHandlerMap
private annotationsByKey: Record<string, Set<MatrixEvent>> = {};
private annotationsBySender: Record<string, Set<MatrixEvent>> = {};
private sortedAnnotationsByKey: [string, Set<MatrixEvent>][] = [];
private targetEvent: MatrixEvent = null;
private targetEvent: MatrixEvent | null = null;
private creationEmitted = false;
private readonly client: MatrixClient;
@@ -107,7 +107,7 @@ export class Relations extends TypedEventEmitter<RelationsEvent, EventHandlerMap
this.addAnnotationToAggregation(event);
} else if (this.relationType === RelationType.Replace && this.targetEvent && !this.targetEvent.isState()) {
const lastReplacement = await this.getLastReplacement();
this.targetEvent.makeReplaced(lastReplacement);
this.targetEvent.makeReplaced(lastReplacement!);
}
event.on(MatrixEventEvent.BeforeRedaction, this.onBeforeRedaction);
@@ -148,7 +148,7 @@ export class Relations extends TypedEventEmitter<RelationsEvent, EventHandlerMap
this.removeAnnotationFromAggregation(event);
} else if (this.relationType === RelationType.Replace && this.targetEvent && !this.targetEvent.isState()) {
const lastReplacement = await this.getLastReplacement();
this.targetEvent.makeReplaced(lastReplacement);
this.targetEvent.makeReplaced(lastReplacement!);
}
this.emit(RelationsEvent.Remove, event);
@@ -189,10 +189,8 @@ export class Relations extends TypedEventEmitter<RelationsEvent, EventHandlerMap
}
private addAnnotationToAggregation(event: MatrixEvent): void {
const { key } = event.getRelation();
if (!key) {
return;
}
const { key } = event.getRelation() ?? {};
if (!key) return;
let eventsForKey = this.annotationsByKey[key];
if (!eventsForKey) {
@@ -218,10 +216,8 @@ export class Relations extends TypedEventEmitter<RelationsEvent, EventHandlerMap
}
private removeAnnotationFromAggregation(event: MatrixEvent): void {
const { key } = event.getRelation();
if (!key) {
return;
}
const { key } = event.getRelation() ?? {};
if (!key) return;
const eventsForKey = this.annotationsByKey[key];
if (eventsForKey) {
@@ -265,7 +261,7 @@ export class Relations extends TypedEventEmitter<RelationsEvent, EventHandlerMap
this.removeAnnotationFromAggregation(redactedEvent);
} else if (this.relationType === RelationType.Replace && this.targetEvent && !this.targetEvent.isState()) {
const lastReplacement = await this.getLastReplacement();
this.targetEvent.makeReplaced(lastReplacement);
this.targetEvent.makeReplaced(lastReplacement!);
}
redactedEvent.removeListener(MatrixEventEvent.BeforeRedaction, this.onBeforeRedaction);
@@ -283,7 +279,7 @@ export class Relations extends TypedEventEmitter<RelationsEvent, EventHandlerMap
* An array of [key, events] pairs sorted by descending event count.
* The events are stored in a Set (which preserves insertion order).
*/
public getSortedAnnotationsByKey() {
public getSortedAnnotationsByKey(): [string, Set<MatrixEvent>][] | null {
if (this.relationType !== RelationType.Annotation) {
// Other relation types are not grouped currently.
return null;
@@ -301,7 +297,7 @@ export class Relations extends TypedEventEmitter<RelationsEvent, EventHandlerMap
* An object with each relation sender as a key and the matching Set of
* events for that sender as a value.
*/
public getAnnotationsBySender() {
public getAnnotationsBySender(): Record<string, Set<MatrixEvent>> | null {
if (this.relationType !== RelationType.Annotation) {
// Other relation types are not grouped currently.
return null;
@@ -335,8 +331,8 @@ export class Relations extends TypedEventEmitter<RelationsEvent, EventHandlerMap
const replaceRelation = this.targetEvent.getServerAggregatedRelation<IAggregatedRelation>(RelationType.Replace);
const minTs = replaceRelation?.origin_server_ts;
const lastReplacement = this.getRelations().reduce((last, event) => {
if (event.getSender() !== this.targetEvent.getSender()) {
const lastReplacement = this.getRelations().reduce<MatrixEvent | null>((last, event) => {
if (event.getSender() !== this.targetEvent!.getSender()) {
return last;
}
if (minTs && minTs > event.getTs()) {
@@ -348,8 +344,8 @@ export class Relations extends TypedEventEmitter<RelationsEvent, EventHandlerMap
return event;
}, null);
if (lastReplacement?.shouldAttemptDecryption()) {
await lastReplacement.attemptDecryption(this.client.crypto);
if (lastReplacement?.shouldAttemptDecryption() && this.client.isCryptoEnabled()) {
await lastReplacement.attemptDecryption(this.client.crypto!);
} else if (lastReplacement?.isBeingDecrypted()) {
await lastReplacement.getDecryptionPromise();
}
+1 -1
View File
@@ -1604,7 +1604,7 @@ export class Room extends ReadReceipt<RoomEmittedEvents, RoomEventHandlerMap> {
// find the earliest unfiltered timeline
let timeline = unfilteredLiveTimeline;
while (timeline.getNeighbouringTimeline(EventTimeline.BACKWARDS)) {
timeline = timeline.getNeighbouringTimeline(EventTimeline.BACKWARDS);
timeline = timeline.getNeighbouringTimeline(EventTimeline.BACKWARDS)!;
}
timelineSet.getLiveTimeline().setPaginationToken(
+7 -7
View File
@@ -83,7 +83,7 @@ export class Thread extends ReadReceipt<EmittedEvents, EventHandlerMap> {
private reEmitter: TypedReEmitter<EmittedEvents, EventHandlerMap>;
private lastEvent: MatrixEvent;
private lastEvent!: MatrixEvent;
private replyCount = 0;
public readonly room: Room;
@@ -185,7 +185,7 @@ export class Thread extends ReadReceipt<EmittedEvents, EventHandlerMap> {
this.lastEvent = events.find(e => (
!e.isRedacted() &&
e.isRelation(THREAD_RELATION_TYPE.name)
)) ?? this.rootEvent;
)) ?? this.rootEvent!;
this.emit(ThreadEvent.Update, this);
};
@@ -267,7 +267,7 @@ export class Thread extends ReadReceipt<EmittedEvents, EventHandlerMap> {
this.client.decryptEventIfNeeded(event, {});
} else if (!toStartOfTimeline &&
this.initialEventsFetched &&
event.localTimestamp > this.lastReply()?.localTimestamp
event.localTimestamp > this.lastReply()!.localTimestamp
) {
this.fetchEditsWhereNeeded(event);
this.addEventToTimeline(event, false);
@@ -289,7 +289,7 @@ export class Thread extends ReadReceipt<EmittedEvents, EventHandlerMap> {
}
}
private getRootEventBundledRelationship(rootEvent = this.rootEvent): IThreadBundledRelationship {
private getRootEventBundledRelationship(rootEvent = this.rootEvent): IThreadBundledRelationship | undefined {
return rootEvent?.getServerAggregatedRelation<IThreadBundledRelationship>(THREAD_RELATION_TYPE.name);
}
@@ -302,7 +302,7 @@ export class Thread extends ReadReceipt<EmittedEvents, EventHandlerMap> {
if (Thread.hasServerSideSupport && bundledRelationship) {
this.replyCount = bundledRelationship.count;
this._currentUserParticipated = bundledRelationship.current_user_participated;
this._currentUserParticipated = !!bundledRelationship.current_user_participated;
const event = new MatrixEvent({
room_id: this.rootEvent.getRoomId(),
@@ -407,7 +407,7 @@ export class Thread extends ReadReceipt<EmittedEvents, EventHandlerMap> {
}
public async fetchEvents(opts: IRelationsRequestOpts = { limit: 20, dir: Direction.Backward }): Promise<{
originalEvent: MatrixEvent;
originalEvent?: MatrixEvent;
events: MatrixEvent[];
nextBatch?: string | null;
prevBatch?: string;
@@ -427,7 +427,7 @@ export class Thread extends ReadReceipt<EmittedEvents, EventHandlerMap> {
// When there's no nextBatch returned with a `from` request we have reached
// the end of the thread, and therefore want to return an empty one
if (!opts.to && !nextBatch) {
if (!opts.to && !nextBatch && originalEvent) {
events = [...events, originalEvent];
}