1
0
mirror of https://github.com/matrix-org/matrix-js-sdk.git synced 2025-12-10 07:22:27 +03:00

Avoid use of Optional type (#5093)

* Avoid use of Optional type

As we are likely to remove dependency on matrix-events-sdk

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Tweak params

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Prettier

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Update test

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
Michael Telatynski
2025-12-04 11:27:43 +00:00
committed by GitHub
parent 942fdf5bee
commit d3bdeb73f5
14 changed files with 39 additions and 56 deletions

View File

@@ -71,7 +71,7 @@ Unless otherwise specified, the following applies to all code:
11. If a variable is not receiving a value on declaration, its type must be defined.
```typescript
let errorMessage: Optional<string>;
let errorMessage: string;
```
12. Objects can use shorthand declarations, including mixing of types.
@@ -150,8 +150,7 @@ Unless otherwise specified, the following applies to all code:
1. When using `any`, a comment explaining why must be present.
27. `import` should be used instead of `require`, as `require` does not have types.
28. Export only what can be reused.
29. Prefer a type like `Optional<X>` (`type Optional<T> = T | null | undefined`) instead
of truly optional parameters.
29. Prefer a type like `X | null` instead of truly optional parameters.
1. A notable exception is when the likelihood of a bug is minimal, such as when a function
takes an argument that is more often not required than required. An example where the
`?` operator is inappropriate is when taking a room ID: typically the caller should
@@ -161,7 +160,7 @@ Unless otherwise specified, the following applies to all code:
```typescript
function doThingWithRoom(
thing: string,
room: Optional<string>, // require the caller to specify
room: string | null, // require the caller to specify
) {
// ...
}

View File

@@ -672,7 +672,7 @@ describe("MatrixClient event timelines", function () {
expect(timeline!.getEvents().find((e) => e.getId() === THREAD_ROOT.event_id!)).toBeTruthy();
});
it("should return undefined when event is not in the thread that the given timelineSet is representing", () => {
it("should return null when event is not in the thread that the given timelineSet is representing", () => {
// @ts-ignore
client.clientOpts.threadSupport = true;
Thread.setServerSideSupport(FeatureSupport.Experimental);
@@ -696,12 +696,12 @@ describe("MatrixClient event timelines", function () {
});
return Promise.all([
expect(client.getEventTimeline(timelineSet, EVENTS[0].event_id!)).resolves.toBeUndefined(),
expect(client.getEventTimeline(timelineSet, EVENTS[0].event_id!)).resolves.toBeNull(),
httpBackend.flushAllExpected(),
]);
});
it("should return undefined when event is within a thread but timelineSet is not", () => {
it("should return null when event is within a thread but timelineSet is not", () => {
// @ts-ignore
client.clientOpts.threadSupport = true;
Thread.setServerSideSupport(FeatureSupport.Experimental);
@@ -723,7 +723,7 @@ describe("MatrixClient event timelines", function () {
});
return Promise.all([
expect(client.getEventTimeline(timelineSet, THREAD_REPLY.event_id!)).resolves.toBeUndefined(),
expect(client.getEventTimeline(timelineSet, THREAD_REPLY.event_id!)).resolves.toBeNull(),
httpBackend.flushAllExpected(),
]);
});

View File

@@ -19,7 +19,7 @@ limitations under the License.
*/
import { mocked } from "jest-mock";
import { M_POLL_KIND_DISCLOSED, M_POLL_RESPONSE, M_POLL_START, type Optional, PollStartEvent } from "matrix-events-sdk";
import { M_POLL_KIND_DISCLOSED, M_POLL_RESPONSE, M_POLL_START, PollStartEvent } from "matrix-events-sdk";
import * as utils from "../test-utils/test-utils";
import { emitPromise, type IMessageOpts } from "../test-utils/test-utils";
@@ -197,8 +197,8 @@ describe("Room", function () {
const addRoomThreads = (
room: Room,
thread1EventTs: Optional<number>,
thread2EventTs: Optional<number>,
thread1EventTs?: number,
thread2EventTs?: number,
): { thread1?: Thread; thread2?: Thread } => {
const result: { thread1?: Thread; thread2?: Thread } = {};
@@ -4159,7 +4159,7 @@ describe("Room", function () {
});
it("when there is only one thread, it should return this one", () => {
const { thread1 } = addRoomThreads(room, 23, null);
const { thread1 } = addRoomThreads(room, 23);
expect(room.getLastThread()).toBe(thread1);
});

View File

@@ -98,7 +98,7 @@ function createLinkedTimelines(): [EventTimeline, EventTimeline] {
describe("TimelineIndex", function () {
beforeEach(() => {
jest.clearAllMocks();
mockClient.getEventTimeline.mockResolvedValue(undefined);
mockClient.getEventTimeline.mockResolvedValue(null);
});
describe("minIndex", function () {
@@ -193,7 +193,7 @@ describe("TimelineWindow", function () {
beforeEach(() => {
jest.clearAllMocks();
mockClient.getEventTimeline.mockResolvedValue(undefined);
mockClient.getEventTimeline.mockResolvedValue(null);
mockClient.paginateEventTimeline.mockResolvedValue(false);
});

View File

@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import { type EitherAnd, NamespacedValue, type Optional, UnstableValue } from "matrix-events-sdk";
import { type EitherAnd, NamespacedValue, UnstableValue } from "matrix-events-sdk";
import { isProvided } from "../extensible_events_v1/utilities.ts";
@@ -125,10 +125,7 @@ export type ExtensibleEventType = NamespacedValue<string, string> | string;
* @param expected - The expected event type.
* @returns True if the given type matches the expected type.
*/
export function isEventTypeSame(
given: Optional<ExtensibleEventType>,
expected: Optional<ExtensibleEventType>,
): boolean {
export function isEventTypeSame(given: ExtensibleEventType | null, expected: ExtensibleEventType | null): boolean {
if (typeof given === "string") {
if (typeof expected === "string") {
return expected === given;

View File

@@ -14,8 +14,6 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import { type Optional } from "matrix-events-sdk";
/**
* Represents a simple Matrix namespaced value. This will assume that if a stable prefix
* is provided that the stable prefix should be used when representing the identifier.
@@ -62,7 +60,7 @@ export class NamespacedValue<S extends string, U extends string> {
// this desperately wants https://github.com/microsoft/TypeScript/pull/26349 at the top level of the class
// so we can instantiate `NamespacedValue<string, _, _>` as a default type for that namespace.
public findIn<T>(obj: any): Optional<T> {
public findIn<T>(obj: any): T | undefined {
let val: T | undefined = undefined;
if (this.name) {
val = obj?.[this.name];

View File

@@ -18,8 +18,6 @@ limitations under the License.
* This is an internal module. See {@link MatrixClient} for the public class.
*/
import { type Optional } from "matrix-events-sdk";
import type { IDeviceKeys, IOneTimeKey } from "./@types/crypto.ts";
import { type ISyncStateData, type SetPresence, SyncApi, type SyncApiOptions, SyncState } from "./sync.ts";
import {
@@ -4501,7 +4499,7 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
* @returns Promise which resolves:
* {@link EventTimeline} including the given event
*/
public async getEventTimeline(timelineSet: EventTimelineSet, eventId: string): Promise<Optional<EventTimeline>> {
public async getEventTimeline(timelineSet: EventTimelineSet, eventId: string): Promise<EventTimeline | null> {
// don't allow any timeline support unless it's been enabled.
if (!this.timelineSupport) {
throw new Error(
@@ -4519,7 +4517,7 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
}
if (timelineSet.thread && this.supportsThreads()) {
return this.getThreadTimeline(timelineSet, eventId);
return (await this.getThreadTimeline(timelineSet, eventId)) ?? null;
}
const res = await this.getEventContext(timelineSet.room.roomId, eventId);
@@ -4533,7 +4531,7 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
const event = mapper(res.event);
if (event.isRelation(THREAD_RELATION_TYPE.name)) {
this.logger.warn("Tried loading a regular timeline at the position of a thread event");
return undefined;
return null;
}
const events = [
// Order events from most recent to oldest (reverse-chronological).
@@ -4665,7 +4663,7 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
{ dir: Direction.Backward, from: res.start, recurse: recurse || undefined },
);
const eventsNewer: IEvent[] = [];
let nextBatch: Optional<string> = res.end;
let nextBatch = res.end;
while (nextBatch) {
const resNewer: IRelationsResponse = await this.fetchRelations(
timelineSet.room.roomId,
@@ -4674,7 +4672,7 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
null,
{ dir: Direction.Forward, from: nextBatch, recurse: recurse || undefined },
);
nextBatch = resNewer.next_batch ?? null;
nextBatch = resNewer.next_batch;
eventsNewer.push(...resNewer.chunk);
}
const events = [
@@ -4718,7 +4716,7 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
* @returns Promise which resolves:
* {@link EventTimeline} timeline with the latest events in the room
*/
public async getLatestTimeline(timelineSet: EventTimelineSet): Promise<Optional<EventTimeline>> {
public async getLatestTimeline(timelineSet: EventTimelineSet): Promise<EventTimeline | null> {
// don't allow any timeline support unless it's been enabled.
if (!this.timelineSupport) {
throw new Error(

View File

@@ -14,8 +14,6 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import { type Optional } from "matrix-events-sdk";
import { ExtensibleEvent } from "./ExtensibleEvent.ts";
import {
type ExtensibleEventType,
@@ -46,7 +44,7 @@ export class MessageEvent extends ExtensibleEvent<ExtensibleAnyMessageEventConte
/**
* The default HTML for the event, if provided.
*/
public readonly html: Optional<string>;
public readonly html?: string;
/**
* All the different renderings of the message. Note that this is the same
@@ -82,7 +80,7 @@ export class MessageEvent extends ExtensibleEvent<ExtensibleAnyMessageEventConte
this.renderings = mmessage;
} else if (isOptionalAString(mtext)) {
this.text = mtext;
this.html = mhtml;
this.html = mhtml ?? undefined;
this.renderings = [{ body: mtext, mimetype: "text/plain" }];
if (this.html) {
this.renderings.push({ body: this.html, mimetype: "text/html" });

View File

@@ -19,7 +19,7 @@ limitations under the License.
* the public classes.
*/
import { type ExtensibleEvent, ExtensibleEvents, type Optional } from "matrix-events-sdk";
import { type ExtensibleEvent, ExtensibleEvents } from "matrix-events-sdk";
import type { IEventDecryptionResult } from "../@types/crypto.ts";
import { logger } from "../logger.ts";
@@ -270,7 +270,7 @@ export class MatrixEvent extends TypedEventEmitter<MatrixEventEmittedEvents, Mat
// addition to a falsy cached event value. We check the flag later on in
// a public getter to decide if the cache is valid.
private _hasCachedExtEv = false;
private _cachedExtEv: Optional<ExtensibleEvent> = undefined;
private _cachedExtEv?: ExtensibleEvent = undefined;
/** If we failed to decrypt this event, the reason for the failure. Otherwise, `null`. */
private _decryptionFailureReason: DecryptionFailureCode | null = null;
@@ -481,9 +481,9 @@ export class MatrixEvent extends TypedEventEmitter<MatrixEventEmittedEvents, Mat
*
* @deprecated Use stable functions where possible.
*/
public get unstableExtensibleEvent(): Optional<ExtensibleEvent> {
public get unstableExtensibleEvent(): ExtensibleEvent | undefined {
if (!this._hasCachedExtEv) {
this._cachedExtEv = ExtensibleEvents.parse(this.getEffectiveEvent());
this._cachedExtEv = ExtensibleEvents.parse(this.getEffectiveEvent()) ?? undefined;
}
return this._cachedExtEv;
}
@@ -789,7 +789,7 @@ export class MatrixEvent extends TypedEventEmitter<MatrixEventEmittedEvents, Mat
* @returns The user's room membership, or `undefined` if the server does
* not report it.
*/
public getMembershipAtEvent(): Optional<Membership | string> {
public getMembershipAtEvent(): Membership | string | undefined {
const unsigned = this.getUnsigned();
return UNSIGNED_MEMBERSHIP_FIELD.findIn<Membership | string>(unsigned);
}

View File

@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import { M_POLL_START, type Optional } from "matrix-events-sdk";
import { M_POLL_START } from "matrix-events-sdk";
import {
DuplicateStrategy,
@@ -1196,7 +1196,7 @@ export class Room extends ReadReceipt<RoomEmittedEvents, RoomEventHandlerMap> {
// Get the main TimelineSet
const timelineSet = this.getUnfilteredTimelineSet();
let newTimeline: Optional<EventTimeline>;
let newTimeline: EventTimeline | null = null;
// If there isn't any event in the timeline, let's go fetch the latest
// event and construct a timeline from it.
//
@@ -2490,7 +2490,7 @@ export class Room extends ReadReceipt<RoomEmittedEvents, RoomEventHandlerMap> {
};
private updateThreadRootEvent = (
timelineSet: Optional<EventTimelineSet>,
timelineSet: EventTimelineSet | undefined,
thread: Thread,
toStartOfTimeline: boolean,
recreateEvent: boolean,

View File

@@ -14,8 +14,6 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import { type Optional } from "matrix-events-sdk";
import { type MatrixClient, PendingEventOrdering } from "../client.ts";
import { TypedReEmitter } from "../ReEmitter.ts";
import { RelationType } from "../@types/event.ts";
@@ -476,7 +474,7 @@ export class Thread extends ReadReceipt<ThreadEmittedEvents, ThreadEventHandlerM
}
}
public async processEvent(event: Optional<MatrixEvent>): Promise<void> {
public async processEvent(event: MatrixEvent | null | undefined): Promise<void> {
if (event) {
this.setEventMetadata(event);
await this.fetchEditsWhereNeeded(event);
@@ -686,14 +684,14 @@ export class Thread extends ReadReceipt<ThreadEmittedEvents, ThreadEventHandlerM
}
}
public setEventMetadata(event: Optional<MatrixEvent>): void {
public setEventMetadata(event: MatrixEvent | null | undefined): void {
if (event) {
EventTimeline.setEventMetadata(event, this.roomState, false);
event.setThread(this);
}
}
public clearEventMetadata(event: Optional<MatrixEvent>): void {
public clearEventMetadata(event: MatrixEvent | null | undefined): void {
if (event) {
event.setThread(undefined);
delete event.event?.unsigned?.["m.relations"]?.[THREAD_RELATION_TYPE.name];
@@ -739,7 +737,7 @@ export class Thread extends ReadReceipt<ThreadEmittedEvents, ThreadEventHandlerM
* A getter for the last event of the thread.
* This might be a synthesized event, if so, it will not emit any events to listeners.
*/
public get replyToEvent(): Optional<MatrixEvent> {
public get replyToEvent(): MatrixEvent | null {
return this.lastPendingEvent ?? this.lastEvent ?? this.lastReply();
}

View File

@@ -23,8 +23,6 @@ limitations under the License.
* for HTTP and WS at some point.
*/
import { type Optional } from "matrix-events-sdk";
import type { SyncCryptoCallbacks } from "./common-crypto/CryptoBackend.ts";
import { User } from "./models/user.ts";
import { NotificationCountType, Room, RoomEvent } from "./models/room.ts";
@@ -208,7 +206,7 @@ export class SyncApi {
private readonly opts: IStoredClientOpts;
private readonly syncOpts: SyncApiOptions;
private _peekRoom: Optional<Room> = null;
private _peekRoom: Room | null = null;
private currentSyncRequest?: Promise<ISyncResponse>;
private abortController?: AbortController;
private syncState: SyncState | null = null;

View File

@@ -14,8 +14,6 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import { type Optional } from "matrix-events-sdk";
import { type Direction, EventTimeline } from "./models/event-timeline.ts";
import { logger } from "./logger.ts";
import { type MatrixClient } from "./client.ts";
@@ -105,7 +103,7 @@ export class TimelineWindow {
public load(initialEventId?: string, initialWindowSize = 20): Promise<void> {
// given an EventTimeline, find the event we were looking for, and initialise our
// fields so that the event in question is in the middle of the window.
const initFields = (timeline: Optional<EventTimeline>): void => {
const initFields = (timeline: EventTimeline | null): void => {
if (!timeline) {
throw new Error("No timeline given to initFields");
}

View File

@@ -20,7 +20,6 @@ limitations under the License.
import unhomoglyph from "unhomoglyph";
import promiseRetry from "p-retry";
import { type Optional } from "matrix-events-sdk";
import { type IEvent, type MatrixEvent } from "./models/event.ts";
import { M_TIMESTAMP } from "./@types/location.ts";
@@ -115,7 +114,7 @@ export function decodeParams(query: string): Record<string, string | string[]> {
* variables with. E.g. `{ "$bar": "baz" }`.
* @returns The result of replacing all template variables e.g. '/foo/baz'.
*/
export function encodeUri(pathTemplate: string, variables: Record<string, Optional<string>>): string {
export function encodeUri(pathTemplate: string, variables: Record<string, string | null | undefined>): string {
for (const key in variables) {
if (!variables.hasOwnProperty(key)) {
continue;