Upgrade to TypeScript 7 (#34208)

* Upgrade to TypeScript 7

for massive tsc speed gains

Those on WebStorm will want to upgrade to EAP to reap the benefits of the new TSGo compiler

Some things (module-api & shared-components) which utilise unplugin-dts (and api-extractor) need to hold a copy of ts6 for its conventional lib format and API. TS7 ships with no API until TS7.1.

Other things which use eslint also need ts6 for typescript-eslint.

Some type changes were necessary as TS7 caught some issues.

* Add knip exception

* Fix bad merge
This commit is contained in:
Michael Telatynski
2026-07-14 08:09:03 +00:00
committed by GitHub
parent c6b52b8a73
commit b6859885a3
18 changed files with 523 additions and 244 deletions
+2 -1
View File
@@ -78,6 +78,7 @@
"@types/minimist": "^1.2.1",
"@types/node": "catalog:",
"@types/pacote": "^11.1.1",
"@typescript/native": "catalog:",
"app-builder-lib": "26.15.3",
"chokidar": "^5.0.0",
"detect-libc": "^2.0.0",
@@ -93,7 +94,7 @@
"rimraf": "^6.0.0",
"shared-types": "workspace:*",
"tar": "^7.5.8",
"typescript": "catalog:",
"typescript": "catalog:ts6",
"vitest": "catalog:"
},
"hakDependencies": {
+2 -1
View File
@@ -159,6 +159,7 @@
"@types/semver": "^7.5.8",
"@types/tar-js": "^0.3.5",
"@types/ua-parser-js": "^0.7.36",
"@typescript/native": "catalog:",
"@vitest/spy": "catalog:",
"babel-jest": "^30.0.0",
"babel-loader": "^10.0.0",
@@ -206,7 +207,7 @@
"stylelint-value-no-unknown-custom-properties": "^6.0.1",
"terser-webpack-plugin": "^5.3.9",
"testcontainers": "^12.0.0",
"typescript": "catalog:",
"typescript": "catalog:ts6",
"util": "^0.12.5",
"vitest": "catalog:",
"vitest-canvas-mock": "^1.1.4",
@@ -12,15 +12,15 @@ import React, { type Ref, type JSX } from "react";
import AccessibleButton, { type ButtonProps } from "../../components/views/elements/AccessibleButton";
type Props<T extends keyof HTMLElementTagNameMap> = ButtonProps<T> & {
type Props = Omit<ButtonProps<"div">, "element" | "ref"> & {
label?: string;
// whether the context menu is currently open
isExpanded: boolean;
ref?: Ref<HTMLElementTagNameMap[T]>;
ref?: Ref<HTMLElement>;
};
// Semantic component for representing the AccessibleButton which launches a <ContextMenu />
export const ContextMenuButton = function <T extends keyof HTMLElementTagNameMap>({
export const ContextMenuButton = function ({
label,
isExpanded,
children,
@@ -28,7 +28,7 @@ export const ContextMenuButton = function <T extends keyof HTMLElementTagNameMap
onContextMenu,
ref,
...props
}: Props<T>): JSX.Element {
}: Props): JSX.Element {
return (
<AccessibleButton
{...props}
@@ -8,24 +8,25 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
Please see LICENSE files in the repository root for full details.
*/
import React, { type JSX } from "react";
import React, { type JSX, type Ref } from "react";
import AccessibleButton, { type ButtonProps } from "../../components/views/elements/AccessibleButton";
type Props<T extends keyof HTMLElementTagNameMap> = ButtonProps<T> & {
type Props = Omit<ButtonProps<"div">, "element" | "ref"> & {
// whether the context menu is currently open
isExpanded: boolean;
ref?: Ref<HTMLElement>;
};
// Semantic component for representing the AccessibleButton which launches a <ContextMenu />
export const ContextMenuTooltipButton = function <T extends keyof HTMLElementTagNameMap>({
export const ContextMenuTooltipButton = function ({
isExpanded,
children,
onClick,
onContextMenu,
ref,
...props
}: Props<T>): JSX.Element {
}: Props): JSX.Element {
return (
<AccessibleButton
{...props}
@@ -15,17 +15,17 @@ import { logger } from "matrix-js-sdk/src/logger";
import SettingsStore from "../../../settings/SettingsStore";
import { _t } from "../../../languageHandler";
import { type SettingLevel } from "../../../settings/SettingLevel";
import { type BooleanSettingKey, defaultWatchManager } from "../../../settings/Settings";
import { type NullableBooleanSettingKey, defaultWatchManager } from "../../../settings/Settings";
interface IProps {
// The setting must be a boolean
name: BooleanSettingKey;
name: NullableBooleanSettingKey;
level: SettingLevel;
roomId?: string; // for per-room settings
label?: string;
isExplicit?: boolean;
hideIfCannotSet?: boolean;
requires?: BooleanSettingKey[];
requires?: NullableBooleanSettingKey[];
onChange?(checked: boolean): void;
}
+7
View File
@@ -372,9 +372,16 @@ export interface Settings {
export type SettingKey = keyof Settings;
export type FeatureSettingKey = Assignable<Settings, IFeature>;
export type BooleanSettingKey = Assignable<Settings, IBaseSetting<boolean>> | FeatureSettingKey;
export type NullableBooleanSettingKey = Assignable<Settings, IBaseSetting<boolean | null>> | FeatureSettingKey;
export type StringSettingKey = Assignable<Settings, IBaseSetting<string>>;
export const SETTINGS: Settings = {
// Used in tests only
"test_setting": {
supportedLevels: [],
default: "",
},
"feature_video_rooms": {
isFeature: true,
labsGroup: LabGroup.VoiceAndVideo,
@@ -8,7 +8,7 @@ Please see LICENSE files in the repository root for full details.
import SettingController from "./SettingController";
import { type SettingLevel } from "../SettingLevel";
import { type BooleanSettingKey } from "../Settings.tsx";
import { type SettingKey, type Settings } from "../Settings.tsx";
import PlatformPeg from "../../PlatformPeg.ts";
/**
@@ -16,11 +16,16 @@ import PlatformPeg from "../../PlatformPeg.ts";
* is also enabled, to prevent cascading undefined behaviour between conflicting
* labs flags.
*/
export default class IncompatibleController extends SettingController {
export default class IncompatibleController<
ControlledSetting extends SettingKey,
WatchedSetting extends SettingKey,
> extends SettingController {
public constructor(
private settingName: BooleanSettingKey,
private forcedValue: any = false,
private incompatibleValue: any | ((v: any) => boolean) = true,
private settingName: WatchedSetting,
private forcedValue: Settings[ControlledSetting]["default"] = false,
private incompatibleValue:
| Settings[WatchedSetting]["default"]
| ((v: Settings[WatchedSetting]["default"]) => boolean) = true,
private readonly disabledMessage?: string,
private readonly forceReload = false,
) {
@@ -9,7 +9,12 @@ Please see LICENSE files in the repository root for full details.
import IncompatibleController from "../../../../src/settings/controllers/IncompatibleController";
import { SettingLevel } from "../../../../src/settings/SettingLevel";
import SettingsStore from "../../../../src/settings/SettingsStore";
import { type FeatureSettingKey } from "../../../../src/settings/Settings.tsx";
declare module "../../../../src/settings/Settings.tsx" {
interface Settings {
test_setting: IBaseSetting<string>;
}
}
describe("IncompatibleController", () => {
const settingsGetValueSpy = jest.spyOn(SettingsStore, "getValue");
@@ -21,17 +26,17 @@ describe("IncompatibleController", () => {
describe("when incompatibleValue is not set", () => {
it("returns true when setting value is true", () => {
// no incompatible value set, defaulted to true
const controller = new IncompatibleController("feature_spotlight" as FeatureSettingKey, { key: null });
const controller = new IncompatibleController("test_setting", { key: null });
settingsGetValueSpy.mockReturnValue(true);
// true === true
expect(controller.incompatibleSetting).toBe(true);
expect(controller.settingDisabled).toEqual(true);
expect(settingsGetValueSpy).toHaveBeenCalledWith("feature_spotlight");
expect(settingsGetValueSpy).toHaveBeenCalledWith("test_setting");
});
it("returns false when setting value is not true", () => {
// no incompatible value set, defaulted to true
const controller = new IncompatibleController("feature_spotlight" as FeatureSettingKey, { key: null });
const controller = new IncompatibleController("test_setting", { key: null });
settingsGetValueSpy.mockReturnValue("test");
expect(controller.incompatibleSetting).toBe(false);
});
@@ -39,21 +44,13 @@ describe("IncompatibleController", () => {
describe("when incompatibleValue is set to a value", () => {
it("returns true when setting value matches incompatible value", () => {
const controller = new IncompatibleController(
"feature_spotlight" as FeatureSettingKey,
{ key: null },
"test",
);
const controller = new IncompatibleController("test_setting", { key: null }, "test");
settingsGetValueSpy.mockReturnValue("test");
expect(controller.incompatibleSetting).toBe(true);
});
it("returns false when setting value is not true", () => {
const controller = new IncompatibleController(
"feature_spotlight" as FeatureSettingKey,
{ key: null },
"test",
);
const controller = new IncompatibleController("test_setting", { key: null }, "test");
settingsGetValueSpy.mockReturnValue("not test");
expect(controller.incompatibleSetting).toBe(false);
});
@@ -62,11 +59,7 @@ describe("IncompatibleController", () => {
describe("when incompatibleValue is set to a function", () => {
it("returns result from incompatibleValue function", () => {
const incompatibleValueFn = jest.fn().mockReturnValue(false);
const controller = new IncompatibleController(
"feature_spotlight" as FeatureSettingKey,
{ key: null },
incompatibleValueFn,
);
const controller = new IncompatibleController("test_setting", { key: null }, incompatibleValueFn);
settingsGetValueSpy.mockReturnValue("test");
expect(controller.incompatibleSetting).toBe(false);
expect(incompatibleValueFn).toHaveBeenCalledWith("test");
@@ -77,7 +70,7 @@ describe("IncompatibleController", () => {
describe("getValueOverride()", () => {
it("returns forced value when setting is incompatible", () => {
settingsGetValueSpy.mockReturnValue(true);
const controller = new IncompatibleController("feature_spotlight" as FeatureSettingKey, { key: null });
const controller = new IncompatibleController("test_setting", { key: null });
expect(
controller.getValueOverride(SettingLevel.ACCOUNT, "$room:server", true, SettingLevel.ACCOUNT),
).toEqual({ key: null });
@@ -85,7 +78,7 @@ describe("IncompatibleController", () => {
it("returns null when setting is not incompatible", () => {
settingsGetValueSpy.mockReturnValue(false);
const controller = new IncompatibleController("feature_spotlight" as FeatureSettingKey, { key: null });
const controller = new IncompatibleController("test_setting", { key: null });
expect(
controller.getValueOverride(SettingLevel.ACCOUNT, "$room:server", true, SettingLevel.ACCOUNT),
).toEqual(null);
+2 -1
View File
@@ -23,7 +23,8 @@
"test-utils": ["./test/test-utils"],
"test-utils/*": ["./test/test-utils/*"],
"jest-mock-vitest-adapter": ["./test/setup/adapter.ts"]
}
},
"skipLibCheck": true
},
"include": [
"./node_modules/matrix-js-sdk/src/@types/*.d.ts",