From f1ea25fddfe061e17faa1ef3dfea927f1dcdd3d9 Mon Sep 17 00:00:00 2001 From: Ben Christel Date: Thu, 5 Sep 2024 12:46:28 -0700 Subject: [PATCH 1/6] Inline changeMatchType --- .../interactive-graph-editor.tsx | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/packages/perseus-editor/src/widgets/interactive-graph-editor/interactive-graph-editor.tsx b/packages/perseus-editor/src/widgets/interactive-graph-editor/interactive-graph-editor.tsx index cc0bd596c9..a0f337d6b1 100644 --- a/packages/perseus-editor/src/widgets/interactive-graph-editor/interactive-graph-editor.tsx +++ b/packages/perseus-editor/src/widgets/interactive-graph-editor/interactive-graph-editor.tsx @@ -168,14 +168,6 @@ class InteractiveGraphEditor extends React.Component { }, }; - changeMatchType = (newValue) => { - const correct = { - ...this.props.correct, - match: newValue, - }; - this.props.onChange({correct: correct}); - }; - changeStartCoords = (coords) => { if (!this.props.graph?.type) { return; @@ -581,7 +573,13 @@ class InteractiveGraphEditor extends React.Component { { + const correct = { + ...this.props.correct, + match: newValue, + }; + this.props.onChange({correct: correct}); + }} // Never uses placeholder, always has value placeholder="" style={styles.singleSelectShort} @@ -644,7 +642,13 @@ class InteractiveGraphEditor extends React.Component { { + const correct = { + ...this.props.correct, + match: newValue, + }; + this.props.onChange({correct: correct}); + }} // Never uses placeholder, always has value placeholder="" style={styles.singleSelectShort} From 2327890558ef441d4f89272cea649be5ca8a22f1 Mon Sep 17 00:00:00 2001 From: Ben Christel Date: Fri, 6 Sep 2024 07:49:18 -0700 Subject: [PATCH 2/6] Give 'correct' prop a real type --- .../interactive-graph-editor.tsx | 134 +++++++++++++----- 1 file changed, 98 insertions(+), 36 deletions(-) diff --git a/packages/perseus-editor/src/widgets/interactive-graph-editor/interactive-graph-editor.tsx b/packages/perseus-editor/src/widgets/interactive-graph-editor/interactive-graph-editor.tsx index a0f337d6b1..e28a1b3658 100644 --- a/packages/perseus-editor/src/widgets/interactive-graph-editor/interactive-graph-editor.tsx +++ b/packages/perseus-editor/src/widgets/interactive-graph-editor/interactive-graph-editor.tsx @@ -1,11 +1,19 @@ import {vector as kvector} from "@khanacademy/kmath"; +import type { + APIOptionsWithDefaults, + LockedFigure, + PerseusImageBackground, + PerseusInteractiveGraphWidgetOptions, +} from "@khanacademy/perseus"; import { components, - interactiveSizes, InteractiveGraphWidget, + interactiveSizes, + PerseusGraphType, SizingUtils, Util, } from "@khanacademy/perseus"; +import type {PropsFor} from "@khanacademy/wonder-blocks-core"; import {View} from "@khanacademy/wonder-blocks-core"; import {OptionItem, SingleSelect} from "@khanacademy/wonder-blocks-dropdown"; import {Checkbox} from "@khanacademy/wonder-blocks-form"; @@ -25,14 +33,9 @@ import SegmentCountSelector from "../../components/segment-count-selector"; import StartCoordsSettings from "../../components/start-coords-settings"; import {shouldShowStartCoordsUI} from "../../components/util"; import {parsePointCount} from "../../util/points"; - -import type { - PerseusImageBackground, - PerseusInteractiveGraphWidgetOptions, - APIOptionsWithDefaults, - LockedFigure, -} from "@khanacademy/perseus"; -import type {PropsFor} from "@khanacademy/wonder-blocks-core"; +import {PerseusGraphTypePolygon, PerseusGraphTypeAngle} from "@khanacademy/perseus/src/perseus-types"; +import invariant from "tiny-invariant"; +import {UnreachableCaseError} from "@khanacademy/wonder-stuff-core"; const {InfoTip} = components; const {containerSizeClass, getInteractiveBoxFromSizeClass} = SizingUtils; @@ -119,7 +122,7 @@ export type Props = { * on the state of the interactive graph previewed at the bottom of the * editor page. */ - correct: any; // TODO(jeremy) + correct: PerseusGraphType; /** * The locked figures to display in the graph area. * Locked figures are graph elements (points, lines, line segmeents, @@ -286,17 +289,16 @@ class InteractiveGraphEditor extends React.Component { showTooltips: this.props.showTooltips, lockedFigures: this.props.lockedFigures, trackInteraction: function () {}, - onChange: (newProps: InteractiveGraphProps) => { + onChange: ({graph: newGraph}: InteractiveGraphProps) => { let correct = this.props.correct; - // @ts-expect-error - TS2532 - Object is possibly 'undefined'. - if (correct.type === newProps.graph.type) { - correct = { - ...correct, - ...newProps.graph, - }; + // TODO(benchristel): can we improve the type of onChange + // so this invariant isn't necessary? + invariant(newGraph != null) + if (correct.type === newGraph.type) { + correct = mergeGraphs(correct, newGraph); } else { // Clear options from previous graph - correct = newProps.graph; + correct = newGraph; } this.props.onChange({ correct: correct, @@ -379,19 +381,19 @@ class InteractiveGraphEditor extends React.Component { } placeholder="" onChange={(newValue) => { - const graph = { - ...this.props.correct, + invariant(this.props.graph?.type === "polygon") + const updates = { numSides: parsePointCount(newValue), coords: null, // reset the snap for UNLIMITED, which // only supports "grid" // From: D6578 snapTo: "grid", - }; + } as const; this.props.onChange({ - correct: graph, - graph: graph, + correct: {...this.props.correct, ...updates}, + graph: {...this.props.graph, ...updates}, }); }} style={styles.singleSelectShort} @@ -414,15 +416,17 @@ class InteractiveGraphEditor extends React.Component { // Never uses placeholder, always has value placeholder="" onChange={(newValue) => { - const graph = { - ...this.props.correct, - snapTo: newValue, + invariant(this.props.correct.type === "polygon", `Expected correct answer type to be polygon, but got ${this.props.correct.type}`) + invariant(this.props.graph?.type === "polygon", `Expected graph type to be polygon, but got ${this.props.graph?.type}`) + + const updates = { + snapTo: newValue as PerseusGraphTypePolygon["snapTo"], coords: null, - }; + } as const this.props.onChange({ - correct: graph, - graph: graph, + correct: {...this.props.correct, ...updates}, + graph: {...this.props.graph, ...updates}, }); }} style={styles.singleSelectShort} @@ -468,6 +472,7 @@ class InteractiveGraphEditor extends React.Component { } onChange={() => { if (this.props.graph?.type === "polygon") { + invariant(this.props.correct.type === "polygon", `Expected graph type to be polygon, but got ${this.props.correct.type}`) this.props.onChange({ correct: { ...this.props.correct, @@ -499,7 +504,7 @@ class InteractiveGraphEditor extends React.Component { !!this.props.correct?.showSides } onChange={() => { - if (this.props.graph?.type === "polygon") { + if (this.props.graph?.type === "polygon" && this.props.correct.type === "polygon") { this.props.onChange({ correct: { ...this.props.correct, @@ -574,11 +579,19 @@ class InteractiveGraphEditor extends React.Component { { + invariant(this.props.correct.type === "polygon", `Expected graph type to be polygon, but got ${this.props.correct.type}`); const correct = { ...this.props.correct, - match: newValue, + // TODO(benchristel): this cast is necessary + // because "exact" is not actually a valid + // value for `match`; a value of undefined + // means exact matching. The code happens + // to work because "exact" falls through + // to the correct else branch in + // InteractiveGraph.validate() + match: newValue as PerseusGraphTypePolygon["match"], }; - this.props.onChange({correct: correct}); + this.props.onChange({correct}); }} // Never uses placeholder, always has value placeholder="" @@ -643,11 +656,17 @@ class InteractiveGraphEditor extends React.Component { { - const correct = { + this.props.onChange({correct: { ...this.props.correct, - match: newValue, - }; - this.props.onChange({correct: correct}); + // TODO(benchristel): this cast is necessary + // because "exact" is not actually a valid + // value for `match`; a value of undefined + // means exact matching. The code happens + // to work because "exact" falls through + // to the correct else branch in + // InteractiveGraph.validate() + match: newValue as PerseusGraphTypeAngle["match"], + }}); }} // Never uses placeholder, always has value placeholder="" @@ -698,6 +717,49 @@ class InteractiveGraphEditor extends React.Component { } } +// Merges two graphs that have the same `type`. Properties defined in `b` +// overwrite properties of the same name in `a`. Throws an exception if the +// types are different or not recognized. +function mergeGraphs(a: PerseusGraphType, b: PerseusGraphType): PerseusGraphType { + if (a.type !== b.type) { + throw new Error(`Cannot merge graphs with different types (${a.type} and ${b.type})`) + } + switch (a.type) { + case "angle": + invariant(b.type === "angle"); + return {...a, ...b}; + case "circle": + invariant(b.type === "circle"); + return {...a, ...b}; + case "linear": + invariant(b.type === "linear"); + return {...a, ...b}; + case "linear-system": + invariant(b.type === "linear-system"); + return {...a, ...b}; + case "point": + invariant(b.type === "point"); + return {...a, ...b}; + case "polygon": + invariant(b.type === "polygon"); + return {...a, ...b}; + case "quadratic": + invariant(b.type === "quadratic"); + return {...a, ...b}; + case "ray": + invariant(b.type === "ray"); + return {...a, ...b}; + case "segment": + invariant(b.type === "segment"); + return {...a, ...b}; + case "sinusoid": + invariant(b.type === "sinusoid"); + return {...a, ...b}; + default: + throw new UnreachableCaseError(a); + } +} + const styles = StyleSheet.create({ singleSelectShort: { // Non-standard spacing, but it's the smallest we can go From f9c447a26643498af807f7867208cd1b08948ecf Mon Sep 17 00:00:00 2001 From: Ben Christel Date: Fri, 6 Sep 2024 07:52:12 -0700 Subject: [PATCH 3/6] Allow coords to be null in interactive graphs The widget editor sets coords to null sometimes, so the graph must be able to handle it. --- packages/perseus/src/perseus-types.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/perseus/src/perseus-types.ts b/packages/perseus/src/perseus-types.ts index baa1aacc51..823bff3d57 100644 --- a/packages/perseus/src/perseus-types.ts +++ b/packages/perseus/src/perseus-types.ts @@ -812,7 +812,7 @@ export type PerseusGraphTypeAngle = { // How to match the answer. If missing, defaults to exact matching. match?: "congruent"; // must have 3 coords - ie [Coord, Coord, Coord] - coords?: [Coord, Coord, Coord]; + coords?: [Coord, Coord, Coord] | null; // The initial coordinates the graph renders with. startCoords?: [Coord, Coord, Coord]; }; @@ -831,7 +831,7 @@ export type PerseusGraphTypeCircle = { export type PerseusGraphTypeLinear = { type: "linear"; // expects 2 coords - coords?: CollinearTuple; + coords?: CollinearTuple | null; // The initial coordinates the graph renders with. startCoords?: CollinearTuple; } & PerseusGraphTypeCommon; @@ -839,7 +839,7 @@ export type PerseusGraphTypeLinear = { export type PerseusGraphTypeLinearSystem = { type: "linear-system"; // expects 2 sets of 2 coords - coords?: CollinearTuple[]; + coords?: CollinearTuple[] | null; // The initial coordinates the graph renders with. startCoords?: CollinearTuple[]; } & PerseusGraphTypeCommon; @@ -848,7 +848,7 @@ export type PerseusGraphTypePoint = { type: "point"; // The number of points if a "point" type. default: 1. "unlimited" if no limit numPoints?: number | "unlimited"; - coords?: ReadonlyArray; + coords?: ReadonlyArray | null; // The initial coordinates the graph renders with. startCoords?: ReadonlyArray; } & PerseusGraphTypeCommon; @@ -865,7 +865,7 @@ export type PerseusGraphTypePolygon = { snapTo?: "grid" | "angles" | "sides"; // How to match the answer. If missing, defaults to exact matching. match?: "similar" | "congruent" | "approx"; - coords?: ReadonlyArray; + coords?: ReadonlyArray | null; // The initial coordinates the graph renders with. startCoords?: ReadonlyArray; } & PerseusGraphTypeCommon; @@ -873,7 +873,7 @@ export type PerseusGraphTypePolygon = { export type PerseusGraphTypeQuadratic = { type: "quadratic"; // expects a list of 3 coords - coords?: [Coord, Coord, Coord]; + coords?: [Coord, Coord, Coord] | null; // The initial coordinates the graph renders with. startCoords?: [Coord, Coord, Coord]; } & PerseusGraphTypeCommon; @@ -883,7 +883,7 @@ export type PerseusGraphTypeSegment = { // The number of segments if a "segment" type. default: 1. Max: 6 numSegments?: number; // Expects a list of Coord tuples. Length should match the `numSegments` value. - coords?: CollinearTuple[]; + coords?: CollinearTuple[] | null; // The initial coordinates the graph renders with. startCoords?: CollinearTuple[]; } & PerseusGraphTypeCommon; @@ -891,7 +891,7 @@ export type PerseusGraphTypeSegment = { export type PerseusGraphTypeSinusoid = { type: "sinusoid"; // Expects a list of 2 Coords - coords?: ReadonlyArray; + coords?: ReadonlyArray | null; // The initial coordinates the graph renders with. startCoords?: ReadonlyArray; } & PerseusGraphTypeCommon; @@ -899,7 +899,7 @@ export type PerseusGraphTypeSinusoid = { export type PerseusGraphTypeRay = { type: "ray"; // Expects a list of 2 Coords - coords?: CollinearTuple; + coords?: CollinearTuple | null; // The initial coordinates the graph renders with. startCoords?: CollinearTuple; } & PerseusGraphTypeCommon; From 05a22d1eec8da4656dd4fbb26317836fc7495155 Mon Sep 17 00:00:00 2001 From: Ben Christel Date: Fri, 6 Sep 2024 07:56:32 -0700 Subject: [PATCH 4/6] Fix lint --- .../interactive-graph-editor.tsx | 111 ++++++++++++------ 1 file changed, 75 insertions(+), 36 deletions(-) diff --git a/packages/perseus-editor/src/widgets/interactive-graph-editor/interactive-graph-editor.tsx b/packages/perseus-editor/src/widgets/interactive-graph-editor/interactive-graph-editor.tsx index e28a1b3658..a72c0b2233 100644 --- a/packages/perseus-editor/src/widgets/interactive-graph-editor/interactive-graph-editor.tsx +++ b/packages/perseus-editor/src/widgets/interactive-graph-editor/interactive-graph-editor.tsx @@ -1,26 +1,20 @@ import {vector as kvector} from "@khanacademy/kmath"; -import type { - APIOptionsWithDefaults, - LockedFigure, - PerseusImageBackground, - PerseusInteractiveGraphWidgetOptions, -} from "@khanacademy/perseus"; import { components, InteractiveGraphWidget, interactiveSizes, - PerseusGraphType, SizingUtils, Util, } from "@khanacademy/perseus"; -import type {PropsFor} from "@khanacademy/wonder-blocks-core"; import {View} from "@khanacademy/wonder-blocks-core"; import {OptionItem, SingleSelect} from "@khanacademy/wonder-blocks-dropdown"; import {Checkbox} from "@khanacademy/wonder-blocks-form"; import {spacing} from "@khanacademy/wonder-blocks-tokens"; import {LabelSmall} from "@khanacademy/wonder-blocks-typography"; +import {UnreachableCaseError} from "@khanacademy/wonder-stuff-core"; import {StyleSheet} from "aphrodite"; import * as React from "react"; +import invariant from "tiny-invariant"; import _ from "underscore"; import LabeledRow from "../../components/graph-locked-figures/labeled-row"; @@ -33,9 +27,15 @@ import SegmentCountSelector from "../../components/segment-count-selector"; import StartCoordsSettings from "../../components/start-coords-settings"; import {shouldShowStartCoordsUI} from "../../components/util"; import {parsePointCount} from "../../util/points"; -import {PerseusGraphTypePolygon, PerseusGraphTypeAngle} from "@khanacademy/perseus/src/perseus-types"; -import invariant from "tiny-invariant"; -import {UnreachableCaseError} from "@khanacademy/wonder-stuff-core"; + +import type { + APIOptionsWithDefaults, + LockedFigure, + PerseusImageBackground, + PerseusInteractiveGraphWidgetOptions, + PerseusGraphType, +} from "@khanacademy/perseus"; +import type {PropsFor} from "@khanacademy/wonder-blocks-core"; const {InfoTip} = components; const {containerSizeClass, getInteractiveBoxFromSizeClass} = SizingUtils; @@ -58,6 +58,8 @@ const POLYGON_SIDES = _.map(_.range(3, 13), function (value) { }); type Range = [min: number, max: number]; +type PerseusGraphTypePolygon = Extract; +type PerseusGraphTypeAngle = Extract; export type Props = { apiOptions: APIOptionsWithDefaults; @@ -293,7 +295,7 @@ class InteractiveGraphEditor extends React.Component { let correct = this.props.correct; // TODO(benchristel): can we improve the type of onChange // so this invariant isn't necessary? - invariant(newGraph != null) + invariant(newGraph != null); if (correct.type === newGraph.type) { correct = mergeGraphs(correct, newGraph); } else { @@ -381,7 +383,9 @@ class InteractiveGraphEditor extends React.Component { } placeholder="" onChange={(newValue) => { - invariant(this.props.graph?.type === "polygon") + invariant( + this.props.graph?.type === "polygon", + ); const updates = { numSides: parsePointCount(newValue), coords: null, @@ -392,8 +396,14 @@ class InteractiveGraphEditor extends React.Component { } as const; this.props.onChange({ - correct: {...this.props.correct, ...updates}, - graph: {...this.props.graph, ...updates}, + correct: { + ...this.props.correct, + ...updates, + }, + graph: { + ...this.props.graph, + ...updates, + }, }); }} style={styles.singleSelectShort} @@ -416,17 +426,29 @@ class InteractiveGraphEditor extends React.Component { // Never uses placeholder, always has value placeholder="" onChange={(newValue) => { - invariant(this.props.correct.type === "polygon", `Expected correct answer type to be polygon, but got ${this.props.correct.type}`) - invariant(this.props.graph?.type === "polygon", `Expected graph type to be polygon, but got ${this.props.graph?.type}`) + invariant( + this.props.correct.type === "polygon", + `Expected correct answer type to be polygon, but got ${this.props.correct.type}`, + ); + invariant( + this.props.graph?.type === "polygon", + `Expected graph type to be polygon, but got ${this.props.graph?.type}`, + ); const updates = { snapTo: newValue as PerseusGraphTypePolygon["snapTo"], coords: null, - } as const + } as const; this.props.onChange({ - correct: {...this.props.correct, ...updates}, - graph: {...this.props.graph, ...updates}, + correct: { + ...this.props.correct, + ...updates, + }, + graph: { + ...this.props.graph, + ...updates, + }, }); }} style={styles.singleSelectShort} @@ -472,7 +494,11 @@ class InteractiveGraphEditor extends React.Component { } onChange={() => { if (this.props.graph?.type === "polygon") { - invariant(this.props.correct.type === "polygon", `Expected graph type to be polygon, but got ${this.props.correct.type}`) + invariant( + this.props.correct.type === + "polygon", + `Expected graph type to be polygon, but got ${this.props.correct.type}`, + ); this.props.onChange({ correct: { ...this.props.correct, @@ -504,7 +530,10 @@ class InteractiveGraphEditor extends React.Component { !!this.props.correct?.showSides } onChange={() => { - if (this.props.graph?.type === "polygon" && this.props.correct.type === "polygon") { + if ( + this.props.graph?.type === "polygon" && + this.props.correct.type === "polygon" + ) { this.props.onChange({ correct: { ...this.props.correct, @@ -579,7 +608,10 @@ class InteractiveGraphEditor extends React.Component { { - invariant(this.props.correct.type === "polygon", `Expected graph type to be polygon, but got ${this.props.correct.type}`); + invariant( + this.props.correct.type === "polygon", + `Expected graph type to be polygon, but got ${this.props.correct.type}`, + ); const correct = { ...this.props.correct, // TODO(benchristel): this cast is necessary @@ -656,17 +688,19 @@ class InteractiveGraphEditor extends React.Component { { - this.props.onChange({correct: { - ...this.props.correct, - // TODO(benchristel): this cast is necessary - // because "exact" is not actually a valid - // value for `match`; a value of undefined - // means exact matching. The code happens - // to work because "exact" falls through - // to the correct else branch in - // InteractiveGraph.validate() - match: newValue as PerseusGraphTypeAngle["match"], - }}); + this.props.onChange({ + correct: { + ...this.props.correct, + // TODO(benchristel): this cast is necessary + // because "exact" is not actually a valid + // value for `match`; a value of undefined + // means exact matching. The code happens + // to work because "exact" falls through + // to the correct else branch in + // InteractiveGraph.validate() + match: newValue as PerseusGraphTypeAngle["match"], + }, + }); }} // Never uses placeholder, always has value placeholder="" @@ -720,9 +754,14 @@ class InteractiveGraphEditor extends React.Component { // Merges two graphs that have the same `type`. Properties defined in `b` // overwrite properties of the same name in `a`. Throws an exception if the // types are different or not recognized. -function mergeGraphs(a: PerseusGraphType, b: PerseusGraphType): PerseusGraphType { +function mergeGraphs( + a: PerseusGraphType, + b: PerseusGraphType, +): PerseusGraphType { if (a.type !== b.type) { - throw new Error(`Cannot merge graphs with different types (${a.type} and ${b.type})`) + throw new Error( + `Cannot merge graphs with different types (${a.type} and ${b.type})`, + ); } switch (a.type) { case "angle": From f70b372268aff6e51692a656e84d86feeb109437 Mon Sep 17 00:00:00 2001 From: Ben Christel Date: Fri, 6 Sep 2024 08:50:39 -0700 Subject: [PATCH 5/6] Add changeset --- .changeset/rude-mangos-boil.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/rude-mangos-boil.md diff --git a/.changeset/rude-mangos-boil.md b/.changeset/rude-mangos-boil.md new file mode 100644 index 0000000000..55ef40376d --- /dev/null +++ b/.changeset/rude-mangos-boil.md @@ -0,0 +1,6 @@ +--- +"@khanacademy/perseus": patch +"@khanacademy/perseus-editor": patch +--- + +Internal: improve type safety of interactive graph editor From 0003cd039661cec165c52cc78859bc728e8567d1 Mon Sep 17 00:00:00 2001 From: Ben Christel Date: Mon, 9 Sep 2024 14:13:14 -0700 Subject: [PATCH 6/6] Add TODOs --- .../interactive-graph-editor/interactive-graph-editor.tsx | 1 + packages/perseus/src/perseus-types.ts | 1 + packages/perseus/src/widgets/interactive-graph.tsx | 1 + .../src/widgets/interactive-graphs/stateful-mafs-graph.tsx | 1 + 4 files changed, 4 insertions(+) diff --git a/packages/perseus-editor/src/widgets/interactive-graph-editor/interactive-graph-editor.tsx b/packages/perseus-editor/src/widgets/interactive-graph-editor/interactive-graph-editor.tsx index a72c0b2233..c7a260a260 100644 --- a/packages/perseus-editor/src/widgets/interactive-graph-editor/interactive-graph-editor.tsx +++ b/packages/perseus-editor/src/widgets/interactive-graph-editor/interactive-graph-editor.tsx @@ -124,6 +124,7 @@ export type Props = { * on the state of the interactive graph previewed at the bottom of the * editor page. */ + // TODO(LEMS-2344): make the type of `correct` more specific correct: PerseusGraphType; /** * The locked figures to display in the graph area. diff --git a/packages/perseus/src/perseus-types.ts b/packages/perseus/src/perseus-types.ts index 823bff3d57..347c9d1828 100644 --- a/packages/perseus/src/perseus-types.ts +++ b/packages/perseus/src/perseus-types.ts @@ -674,6 +674,7 @@ export type PerseusInteractiveGraphWidgetOptions = { // The type of graph graph: PerseusGraphType; // The correct kind of graph, if being used to select function type + // TODO(LEMS-2344): make the type of `correct` more specific correct: PerseusGraphType; // Shapes (points, chords, etc) displayed on the graph that cannot // be moved by the user. diff --git a/packages/perseus/src/widgets/interactive-graph.tsx b/packages/perseus/src/widgets/interactive-graph.tsx index ebbc4df794..a68df25620 100644 --- a/packages/perseus/src/widgets/interactive-graph.tsx +++ b/packages/perseus/src/widgets/interactive-graph.tsx @@ -119,6 +119,7 @@ const makeInvalidTypeError = ( type RenderProps = PerseusInteractiveGraphWidgetOptions; // There's no transform function in exports export type Rubric = { + // TODO(LEMS-2344): make the type of `correct` more specific correct: PerseusGraphType; graph: PerseusGraphType; }; diff --git a/packages/perseus/src/widgets/interactive-graphs/stateful-mafs-graph.tsx b/packages/perseus/src/widgets/interactive-graphs/stateful-mafs-graph.tsx index 82644f8c6d..370a97c780 100644 --- a/packages/perseus/src/widgets/interactive-graphs/stateful-mafs-graph.tsx +++ b/packages/perseus/src/widgets/interactive-graphs/stateful-mafs-graph.tsx @@ -21,6 +21,7 @@ export type StatefulMafsGraphProps = { box: [number, number]; backgroundImage?: InteractiveGraphProps["backgroundImage"]; graph: PerseusGraphType; + // TODO(LEMS-2344): make the type of `correct` more specific correct: PerseusGraphType; lockedFigures?: InteractiveGraphProps["lockedFigures"]; range: InteractiveGraphProps["range"];