+
{formatTitle(title)}
+
{legacyHelper(selected?.id ?? 'none')}
+
+ {units.map((unit) => (
+ -
+
+
+ ))}
+
+
+ );
+}
+
+export default Card;
diff --git a/test/src/legacy.js b/test/src/legacy.js
new file mode 100644
index 0000000..94f66bf
--- /dev/null
+++ b/test/src/legacy.js
@@ -0,0 +1,5 @@
+// Plain JavaScript, type-checked only loosely: `allowJs` is on but `checkJs` is not.
+// Open edX frontends still have plenty of these alongside their TypeScript.
+export function legacyHelper(value) {
+ return String(value).toUpperCase();
+}
diff --git a/test/src/utils.ts b/test/src/utils.ts
new file mode 100644
index 0000000..b90d1ae
--- /dev/null
+++ b/test/src/utils.ts
@@ -0,0 +1,22 @@
+export interface Unit {
+ id: string;
+ title: string;
+ publishedAt?: string;
+}
+
+/** Exercises `satisfies`, optional chaining and nullish coalescing. */
+export function formatTitle(title: string): string {
+ return title.trim() satisfies string;
+}
+
+/** Exercises ESNext lib types (`Array.prototype.at`) against an ES6 target. */
+export function firstUnit(units: Unit[]): Unit | undefined {
+ return units.at(0);
+}
+
+export function isPublished(unit: Unit): boolean {
+ return (unit.publishedAt?.length ?? 0) > 0;
+}
+
+// `isolatedModules` requires type-only re-exports to be marked as such.
+export type { Unit as UnitType };
diff --git a/test/tsconfig.errors.json b/test/tsconfig.errors.json
new file mode 100644
index 0000000..23eeaed
--- /dev/null
+++ b/test/tsconfig.errors.json
@@ -0,0 +1,9 @@
+// The negative fixture: this project is expected to FAIL type checking.
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "noEmit": true
+ },
+ "include": ["errors/**/*", "src/**/*", "types/**/*"],
+ "exclude": ["dist", "node_modules"]
+}
diff --git a/test/tsconfig.json b/test/tsconfig.json
new file mode 100644
index 0000000..e77f0b7
--- /dev/null
+++ b/test/tsconfig.json
@@ -0,0 +1,14 @@
+// Mirrors how an Open edX frontend consumes this package, e.g.
+// https://github.com/openedx/frontend-app-authoring/blob/master/tsconfig.json
+{
+ "extends": "..",
+ "compilerOptions": {
+ "rootDir": ".",
+ "outDir": "dist",
+ "paths": {
+ "@test/*": ["./src/*"]
+ }
+ },
+ "include": ["src/**/*", "types/**/*"],
+ "exclude": ["dist", "errors", "node_modules"]
+}
diff --git a/test/types/assets.d.ts b/test/types/assets.d.ts
new file mode 100644
index 0000000..47b5cc3
--- /dev/null
+++ b/test/types/assets.d.ts
@@ -0,0 +1,12 @@
+// Open edX MFEs import stylesheets and images through webpack loaders. Consumers
+// declare these modules themselves; the fixture does the same so that the asset
+// imports below resolve the way they do in a real frontend app.
+declare module '*.scss' {
+ const classes: Record