Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Screen is incorrectly parameterized #886

Closed
pixelzoom opened this issue Nov 29, 2022 · 16 comments
Closed

Screen is incorrectly parameterized #886

pixelzoom opened this issue Nov 29, 2022 · 16 comments

Comments

@pixelzoom
Copy link
Contributor

In 1e5ca9d, @samreid made this change in Screen.ts:

- class Screen<M extends TModel = TModel, V extends ScreenView = ScreenView> extends PhetioObject {
+ class Screen<M extends TModel = IntentionalAny, V extends ScreenView = ScreenView> extends PhetioObject {

I'm seeing 3 problems related to this:

(1) Developers are not using TModel for their top-level model classes. See for example phetsims/calculus-grapher#117. See also GravityAndOrbitsModel (@samreid), and many other examples.

(2) Developers are not parameterizing their Screen subclasses. See for example phetsims/calculus-grapher#117.

(3) Where developer are parameterizing their Screen subclass, the model M does not implement TModel, but tsc does not complain about this error. See for example greenhouse-effect.PhotonsScreen, where PhotonsModel is not a model class PhotonsScreen extends Screen<PhotonsModel, PhotonsScreenView>

@samreid why do you think this is an appropriate use of IntentionalAny?

@samreid
Copy link
Member

samreid commented Dec 2, 2022

(1) Developers are not using TModel for their top-level model classes. See for example phetsims/calculus-grapher#117. See also GravityAndOrbitsModel (@samreid), and many other examples.

GravityAndOrbitsModel implements TModel because it matches the interface. TypeScript is structurally typed rather than nominally typed, so because GravityAndOrbitsModel matches the TModel interface, it can be used where TModel is expected. I do not see the necessity to change class GravityAndOrbitsModel to class GravityAndOrbitsModel implements TModel if that's what you are advocating.

(3) Where developer are parameterizing their Screen subclass, the model M does not implement TModel, but tsc does not complain about this error.

If I remove the reset method from that hierarchy, then tsc complains because PhotonsModel no longer satisfies the TModel requirements.

(2) Developers are not parameterizing their Screen subclasses. See for example phetsims/calculus-grapher#117.

True, but I'm not sure what kind of problems that could create.

@samreid why do you think this is an appropriate use of IntentionalAny?

The code comment says:

// The IntentionalAny in the model type is due to https://github.com/phetsims/joist/issues/783#issuecomment-1231017213
class Screen<M extends TModel = TModel, V extends ScreenView = ScreenView> extends PhetioObject {

which refers to: #783 (comment)

I tested class Screen<M extends TModel = TModel but it seemed very nontrivial to add correct typing elsewhere that would make that work.

@samreid samreid assigned pixelzoom and unassigned samreid Dec 2, 2022
@pixelzoom
Copy link
Contributor Author

pixelzoom commented Dec 2, 2022

TypeScript is structurally typed rather than nominally typed, so because GravityAndOrbitsModel matches the TModel interface, it can be used where TModel is expected.

That's a poor reason to omit implements TModel. If I followed that reasoning, why would I ever use implements? And why does TypeScript include it?

I do not see the necessity to change class GravityAndOrbitsModel to class GravityAndOrbitsModel implements TModel if that's what you are advocating.

That is what I was advocating. Yeah, it'll work if you omit implements TModel, because of structural typing. But if some part of the TModel API is omitted/wrong in GravityAndOrbitsModel, it's going to show errors at usage sites, not in the definition of GravityAndOrbitsModel. And if TModel changes in the future, you'll get little help from TypeScript identifying what needs to be updated.

And it sounds like you're using IntentionalAny because doing it correctly is too much work. Or am I summarizing incorrectly?

@pixelzoom pixelzoom assigned samreid and unassigned pixelzoom Dec 2, 2022
@samreid
Copy link
Member

samreid commented Feb 14, 2023

Changing

class Screen<M extends TModel = IntentionalAny, V extends ScreenView = ScreenView> extends PhetioObject {

to

class Screen<M extends TModel, V extends ScreenView = ScreenView> extends PhetioObject {

Introduces 80 type errors. I'm not worried about the sim-specific ones. But the ones in Joist would be much more difficult to fix.

And it sounds like you're using IntentionalAny because doing it correctly is too much work.

That is a fair assessment, and in line with our philosophy about getting added value from TypeScript, without spending excessive time to get everything to be type-perfect.

@samreid samreid assigned pixelzoom and unassigned samreid Feb 14, 2023
@pixelzoom
Copy link
Contributor Author

... Introduces 80 type errors. I'm not worried about the sim-specific ones. But the ones in Joist would be much more difficult to fix.

The change that you proposed was as follows, and it introduces 48 TS errors in joist.

class Screen<M extends TModel, V extends ScreenView = ScreenView> extends PhetioObject {

Changing to this reduces the number of TS errors to 27:

class Screen<M extends TModel = TModel, V extends ScreenView = ScreenView> extends PhetioObject {
     4  js/NavigationBar.ts:82
     1  js/PhetButton.ts:142
     1  js/ScreenSelectionSoundGenerator.ts:25
     3  js/selectScreens.ts:129
    14  js/selectScreensTests.ts:115
     4  js/Sim.ts:526

Inspecting the above errors, 100% of them are related to HomeScreen. So there is undoubtedly a type problem with HomeScreen that should be addressed. And I don't see any reason to mask it with IntentionalAny.

Back to @samreid for comment.

@pixelzoom pixelzoom assigned samreid and unassigned pixelzoom Feb 14, 2023
@pixelzoom
Copy link
Contributor Author

pixelzoom commented Feb 14, 2023

There appear to be only 2 unique TS errors related to HomeScreen. Here they are, with examples:

// selectScreens.ts
// TS2345: Argument of type 'HomeScreen' is not assignable to parameter of type 'Screen '.
screens.unshift( homeScreen );

// PhetButton.ts
// TS2367: This comparison appears to be unintentional because the types 'Screen ' and 'HomeScreen | null' have no overlap.
 const showHomeScreen = screen === sim.homeScreen;

@pixelzoom
Copy link
Contributor Author

I'd start with this:

- class HomeScreenModel {
+ class HomeScreenModel implements TModel {

@samreid
Copy link
Member

samreid commented Feb 14, 2023

Here's my initial start on this issue:

Subject: [PATCH] Move LinkableElement to a top-level type, improve documentation, use LinkableProperty and LinkableReadOnlyProperty, see https://github.com/phetsims/axon/issues/414
---
Index: main/acid-base-solutions/js/mysolution/MySolutionScreen.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/main/acid-base-solutions/js/mysolution/MySolutionScreen.ts b/main/acid-base-solutions/js/mysolution/MySolutionScreen.ts
--- a/main/acid-base-solutions/js/mysolution/MySolutionScreen.ts	(revision 58e33883fb21e5266e878f09ba45b8d55ad55b3f)
+++ b/main/acid-base-solutions/js/mysolution/MySolutionScreen.ts	(date 1676415692457)
@@ -18,7 +18,7 @@
 import MySolutionModel from './model/MySolutionModel.js';
 import MySolutionScreenView from './view/MySolutionScreenView.js';
 
-export default class MySolutionScreen extends Screen {
+export default class MySolutionScreen extends Screen<MySolutionModel, MySolutionScreenView> {
 
   public constructor( tandem: Tandem ) {
 
Index: main/joist/js/Screen.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/main/joist/js/Screen.ts b/main/joist/js/Screen.ts
--- a/main/joist/js/Screen.ts	(revision 645f5bfedd59ebe8628b1ddf148fa56c1aea195a)
+++ b/main/joist/js/Screen.ts	(date 1676415483098)
@@ -30,7 +30,6 @@
 import ScreenIcon from './ScreenIcon.js';
 import ScreenView from './ScreenView.js';
 import PickRequired from '../../phet-core/js/types/PickRequired.js';
-import IntentionalAny from '../../phet-core/js/types/IntentionalAny.js';
 import Multilink from '../../axon/js/Multilink.js';
 import TModel from './TModel.js';
 import PatternStringProperty from '../../axon/js/PatternStringProperty.js';
@@ -74,7 +73,7 @@
 
 // Parameterized on M=Model and V=View
 // The IntentionalAny in the model type is due to https://github.com/phetsims/joist/issues/783#issuecomment-1231017213
-class Screen<M extends TModel = IntentionalAny, V extends ScreenView = ScreenView> extends PhetioObject {
+class Screen<M extends TModel = TModel, V extends ScreenView = ScreenView> extends PhetioObject {
 
   public backgroundColorProperty: Property<Color> | Property<string> | Property<Color | string>;
 
Index: main/joist/js/HomeScreenModel.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/main/joist/js/HomeScreenModel.ts b/main/joist/js/HomeScreenModel.ts
--- a/main/joist/js/HomeScreenModel.ts	(revision 645f5bfedd59ebe8628b1ddf148fa56c1aea195a)
+++ b/main/joist/js/HomeScreenModel.ts	(date 1676415429570)
@@ -14,8 +14,9 @@
 import Tandem from '../../tandem/js/Tandem.js';
 import joist from './joist.js';
 import Screen from './Screen.js';
+import TModel from './TModel.js';
 
-class HomeScreenModel {
+class HomeScreenModel implements TModel {
   public simScreens: Screen[]; // screens in the simulations that are not the HomeScreen
   public screenProperty: Property<Screen>;
   public selectedScreenProperty: Property<Screen>;
Index: main/acid-base-solutions/js/introduction/IntroductionScreen.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/main/acid-base-solutions/js/introduction/IntroductionScreen.ts b/main/acid-base-solutions/js/introduction/IntroductionScreen.ts
--- a/main/acid-base-solutions/js/introduction/IntroductionScreen.ts	(revision 58e33883fb21e5266e878f09ba45b8d55ad55b3f)
+++ b/main/acid-base-solutions/js/introduction/IntroductionScreen.ts	(date 1676415610603)
@@ -18,7 +18,7 @@
 import IntroductionModel from './model/IntroductionModel.js';
 import IntroductionScreenView from './view/IntroductionScreenView.js';
 
-export default class IntroductionScreen extends Screen {
+export default class IntroductionScreen extends Screen<IntroductionModel, IntroductionScreenView> {
 
   public constructor( tandem: Tandem ) {
 

After this change, there are 101 type errors:


node js/scripts/absolute-tsc.js ../chipper/tsconfig/all
/Users/samreid/apache-document-root/main/acid-base-solutions/js/acid-base-solutions-main.ts(24,95): error TS2345: Argument of type '(IntroductionScreen | MySolutionScreen)[]' is not assignable to parameter of type 'Screen<TModel, ScreenView>[]'.
  Type 'IntroductionScreen | MySolutionScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
    Type 'IntroductionScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
      Types of property 'createView' are incompatible.
        Type 'CreateView<IntroductionModel, IntroductionScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
          Type 'TModel' is missing the following properties from type 'IntroductionModel': solutionTypeProperty, solutionsMap, pHProperty, beaker, and 6 more.
/Users/samreid/apache-document-root/main/beers-law-lab/js/beers-law-lab-main.ts(21,86): error TS2345: Argument of type '(BeersLawScreen | ConcentrationScreen)[]' is not assignable to parameter of type 'Screen<TModel, ScreenView>[]'.
  Type 'BeersLawScreen | ConcentrationScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
    Type 'BeersLawScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
      Types of property 'createView' are incompatible.
        Type 'CreateView<BeersLawModel, BeersLawScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
          Type 'TModel' is missing the following properties from type 'BeersLawModel': solutions, solutionProperty, cuvette, light, and 5 more.
/Users/samreid/apache-document-root/main/build-a-nucleus/js/build-a-nucleus-main.ts(54,5): error TS2322: Type 'DecayScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
  Types of property 'createView' are incompatible.
    Type 'CreateView<DecayModel, DecayScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
      Type 'TModel' is missing the following properties from type 'DecayModel': halfLifeNumberProperty, protonEmissionEnabledProperty, neutronEmissionEnabledProperty, betaMinusDecayEnabledProperty, and 20 more.
/Users/samreid/apache-document-root/main/build-a-nucleus/js/build-a-nucleus-main.ts(55,5): error TS2322: Type 'ChartIntroScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
  Types of property 'createView' are incompatible.
    Type 'CreateView<ChartIntroModel, ChartIntroScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
      Type 'TModel' is missing the following properties from type 'ChartIntroModel': particleNucleus, getParticleToReturn, getParticleDestination, isStableBooleanProperty, and 15 more.
/Users/samreid/apache-document-root/main/buoyancy/js/buoyancy-main.ts(37,5): error TS2322: Type 'IntroScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
  Types of property 'createView' are incompatible.
    Type 'CreateView<BuoyancyIntroModel, BuoyancyIntroScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
      Type 'TModel' is missing the following properties from type 'BuoyancyIntroModel': BlockSet, blockSetProperty, createMassesCallback, regenerateMassesCallback, and 33 more.
/Users/samreid/apache-document-root/main/buoyancy/js/buoyancy-main.ts(38,5): error TS2322: Type 'ExploreScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
  Types of property 'createView' are incompatible.
    Type 'CreateView<BuoyancyExploreModel, BuoyancyExploreScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
      Type 'TModel' is missing the following properties from type 'BuoyancyExploreModel': modeProperty, primaryMass, secondaryMass, densityExpandedProperty, and 29 more.
/Users/samreid/apache-document-root/main/buoyancy/js/buoyancy-main.ts(39,5): error TS2322: Type 'ShapesScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
  Types of property 'createView' are incompatible.
    Type 'CreateView<BuoyancyShapesModel, BuoyancyShapesScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
      Type 'TModel' is missing the following properties from type 'BuoyancyShapesModel': modeProperty, secondaryMassVisibleProperty, densityExpandedProperty, leftScale, and 39 more.
/Users/samreid/apache-document-root/main/buoyancy/js/buoyancy-main.ts(40,5): error TS2322: Type 'ApplicationsScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
  Types of property 'createView' are incompatible.
    Type 'CreateView<BuoyancyApplicationsModel, BuoyancyApplicationsScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
      Type 'TModel' is missing the following properties from type 'BuoyancyApplicationsModel': sceneProperty, densityExpandedProperty, bottle, block, and 32 more.
/Users/samreid/apache-document-root/main/calculus-grapher/js/calculus-grapher-main.ts(54,90): error TS2345: Argument of type '(DerivativeScreen | IntegralScreen | LabScreen | AdvancedScreen)[]' is not assignable to parameter of type 'Screen<TModel, ScreenView>[]'.
  Type 'DerivativeScreen | IntegralScreen | LabScreen | AdvancedScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
    Type 'DerivativeScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
      Types of property 'createView' are incompatible.
        Type 'CreateView<DerivativeModel, DerivativeScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
          Type 'TModel' is missing the following properties from type 'DerivativeModel': graphSets, graphSetProperty, curveManipulationProperties, predictEnabledProperty, and 14 more.
/Users/samreid/apache-document-root/main/center-and-variability/js/center-and-variability-main.ts(42,5): error TS2322: Type 'MedianScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
  Types of property 'createView' are incompatible.
    Type 'CreateView<MedianModel, MedianScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
      Type 'TModel' is missing the following properties from type 'MedianModel': soccerPlayerGroup, nextBallToKickProperty, numberOfScheduledSoccerBallsToKickProperty, numberOfRemainingKickableSoccerBallsProperty, and 42 more.
/Users/samreid/apache-document-root/main/center-and-variability/js/center-and-variability-main.ts(43,5): error TS2322: Type 'MeanAndMedianScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
  Types of property 'createView' are incompatible.
    Type 'CreateView<MeanAndMedianModel, MeanAndMedianScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
      Type 'TModel' is missing the following properties from type 'MeanAndMedianModel': soccerPlayerGroup, nextBallToKickProperty, numberOfScheduledSoccerBallsToKickProperty, numberOfRemainingKickableSoccerBallsProperty, and 42 more.
/Users/samreid/apache-document-root/main/circuit-construction-kit-dc-virtual-lab/js/circuit-construction-kit-dc-virtual-lab-main.ts(28,5): error TS2322: Type 'LabScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
/Users/samreid/apache-document-root/main/circuit-construction-kit-dc/js/circuit-construction-kit-dc-main.ts(40,69): error TS2345: Argument of type '(IntroScreen | LabScreen)[]' is not assignable to parameter of type 'Screen<TModel, ScreenView>[]'.
  Type 'IntroScreen | LabScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
    Type 'LabScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
      Types of property 'createView' are incompatible.
        Type 'CreateView<LabModel, LabScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
          Type 'TModel' is missing the following properties from type 'LabModel': zoomAnimation, viewTypeProperty, addRealBulbsProperty, circuit, and 16 more.
/Users/samreid/apache-document-root/main/circuit-construction-kit-dc/js/intro/IntroScreen.ts(64,37): error TS2345: Argument of type 'TModel' is not assignable to parameter of type 'IntroModel'.
  Type 'TModel' is missing the following properties from type 'IntroModel': zoomAnimation, viewTypeProperty, addRealBulbsProperty, circuit, and 16 more.
/Users/samreid/apache-document-root/main/concentration/js/concentration-main.ts(19,83): error TS2345: Argument of type 'ConcentrationScreen[]' is not assignable to parameter of type 'Screen<TModel, ScreenView>[]'.
  Type 'ConcentrationScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
    Types of property 'createView' are incompatible.
      Type 'CreateView<ConcentrationModel, ConcentrationScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
        Type 'TModel' is missing the following properties from type 'ConcentrationModel': solutes, soluteProperty, soluteFormProperty, solution, and 20 more.
/Users/samreid/apache-document-root/main/density/js/density-main.ts(37,5): error TS2322: Type 'IntroScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
  Types of property 'createView' are incompatible.
    Type 'CreateView<DensityIntroModel, DensityIntroScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
      Type 'TModel' is missing the following properties from type 'DensityIntroModel': modeProperty, primaryMass, secondaryMass, densityExpandedProperty, and 29 more.
/Users/samreid/apache-document-root/main/density/js/density-main.ts(38,5): error TS2322: Type 'CompareScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
  Types of property 'createView' are incompatible.
    Type 'CreateView<DensityCompareModel, DensityCompareScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
      Type 'TModel' is missing the following properties from type 'DensityCompareModel': massProperty, volumeProperty, densityProperty, BlockSet, and 36 more.
/Users/samreid/apache-document-root/main/density/js/density-main.ts(39,5): error TS2322: Type 'MysteryScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
  Types of property 'createView' are incompatible.
    Type 'CreateView<DensityMysteryModel, DensityMysteryScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
      Type 'TModel' is missing the following properties from type 'DensityMysteryModel': densityTableExpandedProperty, scale, BlockSet, blockSetProperty, and 35 more.
/Users/samreid/apache-document-root/main/diffusion/js/diffusion-main.ts(24,72): error TS2345: Argument of type 'DiffusionScreen[]' is not assignable to parameter of type 'Screen<TModel, ScreenView>[]'.
  Type 'DiffusionScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
    Types of property 'createView' are incompatible.
      Type 'CreateView<DiffusionModel, DiffusionScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
        Type 'TModel' is missing the following properties from type 'DiffusionModel': particles1, particles2, container, leftSettings, and 21 more.
/Users/samreid/apache-document-root/main/equality-explorer-basics/js/equality-explorer-basics-main.ts(24,105): error TS2345: Argument of type '(BasicsScreen | LabScreen)[]' is not assignable to parameter of type 'Screen<TModel, ScreenView>[]'.
  Type 'BasicsScreen | LabScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
    Type 'BasicsScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
/Users/samreid/apache-document-root/main/equality-explorer-two-variables/js/equality-explorer-two-variables-main.ts(22,118): error TS2345: Argument of type 'TwoVariablesScreen[]' is not assignable to parameter of type 'Screen<TModel, ScreenView>[]'.
  Type 'TwoVariablesScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
    Types of property 'createView' are incompatible.
      Type 'CreateView<TwoVariablesModel, TwoVariablesScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
        Type 'TModel' is missing the following properties from type 'TwoVariablesModel': scenes, sceneProperty, dispose, deactivate, and 56 more.
/Users/samreid/apache-document-root/main/equality-explorer/js/equality-explorer-main.ts(31,92): error TS2345: Argument of type '(BasicsScreen | NumbersScreen | OperationsScreen | SolveItScreen | VariablesScreen)[]' is not assignable to parameter of type 'Screen<TModel, ScreenView>[]'.
  Type 'BasicsScreen | NumbersScreen | OperationsScreen | SolveItScreen | VariablesScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
    Type 'BasicsScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
      Types of property 'createView' are incompatible.
        Type 'CreateView<BasicsModel, BasicsScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
          Type 'TModel' is missing the following properties from type 'BasicsModel': scenes, sceneProperty, dispose, deactivate, and 56 more.
/Users/samreid/apache-document-root/main/function-builder-basics/js/function-builder-basics-main.ts(30,103): error TS2345: Argument of type '(FBBMysteryScreen | PatternsScreen)[]' is not assignable to parameter of type 'Screen<TModel, ScreenView>[]'.
  Type 'FBBMysteryScreen | PatternsScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
    Type 'FBBMysteryScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
      Types of property 'createView' are incompatible.
        Type 'CreateView<FBBMysteryModel, FBBMysteryScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
          Type 'TModel' is missing the following properties from type 'FBBMysteryModel': scenes, selectedSceneProperty
/Users/samreid/apache-document-root/main/gas-properties/js/gas-properties-main.ts(31,86): error TS2345: Argument of type '(DiffusionScreen | IdealScreen | EnergyScreen | ExploreScreen)[]' is not assignable to parameter of type 'Screen<TModel, ScreenView>[]'.
  Type 'DiffusionScreen | IdealScreen | EnergyScreen | ExploreScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
    Type 'DiffusionScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
/Users/samreid/apache-document-root/main/gases-intro/js/gases-intro-main.ts(37,80): error TS2345: Argument of type '(IntroScreen | LawsScreen)[]' is not assignable to parameter of type 'Screen<TModel, ScreenView>[]'.
  Type 'IntroScreen | LawsScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
    Type 'IntroScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
      Types of property 'createView' are incompatible.
        Type 'CreateView<IdealModel, IdealScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
          Type 'TModel' is missing the following properties from type 'IdealModel': holdConstantProperty, heatCoolFactorProperty, particleParticleCollisionsEnabledProperty, container, and 22 more.
/Users/samreid/apache-document-root/main/geometric-optics/js/GOSim.ts(58,7): error TS2322: Type 'LensScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
  Types of property 'createView' are incompatible.
    Type 'CreateView<LensModel, LensScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
      Type 'TModel' is missing the following properties from type 'LensModel': lens, opticalObjectChoiceProperty, raysTypeProperty, lightPropagationEnabledProperty, and 11 more.
/Users/samreid/apache-document-root/main/geometric-optics/js/GOSim.ts(62,7): error TS2322: Type 'MirrorScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
  Types of property 'createView' are incompatible.
    Type 'CreateView<MirrorModel, MirrorScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
      Type 'TModel' is missing the following properties from type 'MirrorModel': mirror, opticalObjectChoiceProperty, raysTypeProperty, lightPropagationEnabledProperty, and 11 more.
/Users/samreid/apache-document-root/main/graphing-slope-intercept/js/linegame/GSILineGameScreen.ts(32,43): error TS2345: Argument of type 'TModel' is not assignable to parameter of type 'GSILineGameModel'.
  Type 'TModel' is missing the following properties from type 'GSILineGameModel': challengeFactories, levelProperty, soundEnabledProperty, timerEnabledProperty, and 24 more.
/Users/samreid/apache-document-root/main/gravity-and-orbits/js/gravity-and-orbits-main.ts(52,83): error TS2322: Type 'ModelScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
  Types of property 'createView' are incompatible.
    Type 'CreateView<ModelModel, GravityAndOrbitsScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
      Type 'TModel' is missing the following properties from type 'ModelModel': showGravityForceProperty, showVelocityProperty, showPathProperty, showGridProperty, and 14 more.
/Users/samreid/apache-document-root/main/gravity-and-orbits/js/gravity-and-orbits-main.ts(52,96): error TS2322: Type 'ToScaleScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
  Types of property 'createView' are incompatible.
    Type 'CreateView<ToScaleModel, GravityAndOrbitsScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
      Type 'TModel' is missing the following properties from type 'ToScaleModel': showGravityForceProperty, showVelocityProperty, showPathProperty, showGridProperty, and 14 more.
/Users/samreid/apache-document-root/main/greenhouse-effect/js/greenhouse-effect-main.ts(41,7): error TS2322: Type 'WavesScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
  Types of property 'createView' are incompatible.
    Type 'CreateView<WavesModel, WavesScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
      Type 'TModel' is missing the following properties from type 'WavesModel': waveGroup, wavesChangedEmitter, sunWaveSource, groundWaveSource, and 101 more.
/Users/samreid/apache-document-root/main/greenhouse-effect/js/greenhouse-effect-main.ts(42,7): error TS2322: Type 'PhotonsScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
  Types of property 'createView' are incompatible.
    Type 'CreateView<PhotonsModel, PhotonsScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
      Type 'TModel' is missing the following properties from type 'PhotonsModel': photonCollection, photonsPassingThroughCloud, cloudBounds, stepModel, and 89 more.
/Users/samreid/apache-document-root/main/greenhouse-effect/js/greenhouse-effect-main.ts(43,7): error TS2322: Type 'LayerModelScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
  Types of property 'createView' are incompatible.
    Type 'CreateView<LayerModelModel, LayerModelScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
      Type 'TModel' is missing the following properties from type 'LayerModelModel': numberOfActiveAtmosphereLayersProperty, layersInfraredAbsorbanceProperty, photonCollection, stepModel, and 82 more.
/Users/samreid/apache-document-root/main/hookes-law/js/hookes-law-main.ts(25,78): error TS2345: Argument of type '(EnergyScreen | IntroScreen | SystemsScreen)[]' is not assignable to parameter of type 'Screen<TModel, ScreenView>[]'.
  Type 'EnergyScreen | IntroScreen | SystemsScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
    Type 'EnergyScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
      Types of property 'createView' are incompatible.
        Type 'CreateView<EnergyModel, EnergyScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
          Property 'system' is missing in type 'TModel' but required in type 'EnergyModel'.
/Users/samreid/apache-document-root/main/hookes-law/js/intro/IntroScreen.ts(31,37): error TS2345: Argument of type 'TModel' is not assignable to parameter of type 'IntroModel'.
  Type 'TModel' is missing the following properties from type 'IntroModel': system1, system2
/Users/samreid/apache-document-root/main/hookes-law/js/systems/SystemsScreen.ts(31,39): error TS2345: Argument of type 'TModel' is not assignable to parameter of type 'SystemsModel'.
  Type 'TModel' is missing the following properties from type 'SystemsModel': seriesSystem, parallelSystem
/Users/samreid/apache-document-root/main/joist/js/NavigationBar.ts(82,30): error TS2367: This comparison appears to be unintentional because the types 'Screen<TModel, ScreenView>' and 'HomeScreen | null' have no overlap.
/Users/samreid/apache-document-root/main/joist/js/NavigationBar.ts(114,87): error TS2367: This comparison appears to be unintentional because the types 'Screen<TModel, ScreenView>' and 'HomeScreen | null' have no overlap.
/Users/samreid/apache-document-root/main/joist/js/NavigationBar.ts(177,18): error TS2367: This comparison appears to be unintentional because the types 'Screen<TModel, ScreenView>' and 'HomeScreen | null' have no overlap.
/Users/samreid/apache-document-root/main/joist/js/NavigationBar.ts(194,13): error TS2322: Type 'HomeScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
  Types of property 'createView' are incompatible.
    Type 'CreateView<HomeScreenModel, HomeScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
      Type 'TModel' is missing the following properties from type 'HomeScreenModel': simScreens, screenProperty, selectedScreenProperty, activeSimScreensProperty
/Users/samreid/apache-document-root/main/joist/js/PhetButton.ts(142,32): error TS2367: This comparison appears to be unintentional because the types 'Screen<TModel, ScreenView>' and 'HomeScreen | null' have no overlap.
/Users/samreid/apache-document-root/main/joist/js/ScreenSelectionSoundGenerator.ts(25,12): error TS2367: This comparison appears to be unintentional because the types 'Screen<TModel, ScreenView>' and 'HomeScreen | null' have no overlap.
/Users/samreid/apache-document-root/main/joist/js/selectScreens.ts(129,22): error TS2345: Argument of type 'HomeScreen' is not assignable to parameter of type 'Screen<TModel, ScreenView>'.
/Users/samreid/apache-document-root/main/joist/js/selectScreens.ts(151,27): error TS2345: Argument of type 'Screen<TModel, ScreenView> | HomeScreen' is not assignable to parameter of type 'Screen<TModel, ScreenView>'.
  Type 'HomeScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
/Users/samreid/apache-document-root/main/joist/js/selectScreens.ts(160,5): error TS2322: Type 'Screen<TModel, ScreenView> | HomeScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
  Type 'HomeScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
/Users/samreid/apache-document-root/main/joist/js/selectScreensTests.ts(115,5): error TS2322: Type 'HomeScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
/Users/samreid/apache-document-root/main/joist/js/selectScreensTests.ts(117,16): error TS2322: Type 'HomeScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
/Users/samreid/apache-document-root/main/joist/js/selectScreensTests.ts(122,5): error TS2322: Type 'HomeScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
/Users/samreid/apache-document-root/main/joist/js/selectScreensTests.ts(124,16): error TS2322: Type 'HomeScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
/Users/samreid/apache-document-root/main/joist/js/selectScreensTests.ts(136,5): error TS2322: Type 'HomeScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
/Users/samreid/apache-document-root/main/joist/js/selectScreensTests.ts(138,16): error TS2322: Type 'HomeScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
/Users/samreid/apache-document-root/main/joist/js/selectScreensTests.ts(143,5): error TS2322: Type 'HomeScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
/Users/samreid/apache-document-root/main/joist/js/selectScreensTests.ts(145,16): error TS2322: Type 'HomeScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
/Users/samreid/apache-document-root/main/joist/js/selectScreensTests.ts(150,5): error TS2322: Type 'HomeScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
/Users/samreid/apache-document-root/main/joist/js/selectScreensTests.ts(152,16): error TS2322: Type 'HomeScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
/Users/samreid/apache-document-root/main/joist/js/selectScreensTests.ts(164,5): error TS2322: Type 'HomeScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
/Users/samreid/apache-document-root/main/joist/js/selectScreensTests.ts(166,16): error TS2322: Type 'HomeScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
/Users/samreid/apache-document-root/main/joist/js/selectScreensTests.ts(173,16): error TS2322: Type 'HomeScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
/Users/samreid/apache-document-root/main/joist/js/selectScreensTests.ts(180,16): error TS2322: Type 'HomeScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
/Users/samreid/apache-document-root/main/joist/js/Sim.ts(526,12): error TS2367: This comparison appears to be unintentional because the types 'Screen<TModel, ScreenView>' and 'HomeScreen | null' have no overlap.
/Users/samreid/apache-document-root/main/joist/js/Sim.ts(531,54): error TS2339: Property 'model' does not exist on type 'never'.
/Users/samreid/apache-document-root/main/joist/js/Sim.ts(533,27): error TS2339: Property 'model' does not exist on type 'never'.
/Users/samreid/apache-document-root/main/joist/js/Sim.ts(890,106): error TS2367: This comparison appears to be unintentional because the types 'HomeScreen | null' and 'Screen<TModel, ScreenView>' have no overlap.
/Users/samreid/apache-document-root/main/mean-share-and-balance/js/mean-share-and-balance-main.ts(34,5): error TS2322: Type 'IntroScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
  Types of property 'createView' are incompatible.
    Type 'CreateView<IntroModel, IntroScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
      Type 'TModel' is missing the following properties from type 'IntroModel': numberOfCupsRange, dragRange, cupRange, numberOfCupsProperty, and 20 more.
/Users/samreid/apache-document-root/main/mean-share-and-balance/js/mean-share-and-balance-main.ts(35,5): error TS2322: Type 'LevelingOutScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
  Types of property 'createView' are incompatible.
    Type 'CreateView<LevelingOutModel, LevelingOutScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
      Type 'TModel' is missing the following properties from type 'LevelingOutModel': numberOfPeopleRangeProperty, numberOfPeopleProperty, platesArray, peopleArray, and 22 more.
/Users/samreid/apache-document-root/main/models-of-the-hydrogen-atom/js/models-of-the-hydrogen-atom-main.ts(45,45): error TS2345: Argument of type '(EnergyLevelsScreen | SpectraScreen)[]' is not assignable to parameter of type 'Screen<TModel, ScreenView>[]'.
  Type 'EnergyLevelsScreen | SpectraScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
    Type 'EnergyLevelsScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
      Types of property 'createView' are incompatible.
        Type 'CreateView<EnergyLevelsModel, EnergyLevelsScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
          Type 'TModel' is missing the following properties from type 'EnergyLevelsModel': bohrModel, deBroglieModel, schrodingerModel, dispose, and 16 more.
/Users/samreid/apache-document-root/main/molecule-polarity/js/molecule-polarity-main.ts(27,92): error TS2345: Argument of type '(RealMoleculesScreen | ThreeAtomsScreen | TwoAtomsScreen)[]' is not assignable to parameter of type 'Screen<TModel, ScreenView>[]'.
  Type 'RealMoleculesScreen | ThreeAtomsScreen | TwoAtomsScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
    Type 'RealMoleculesScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
      Types of property 'createView' are incompatible.
        Type 'CreateView<RealMoleculesModel, RealMoleculesScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
          Type 'TModel' is missing the following properties from type 'RealMoleculesModel': molecules, moleculeProperty, tandem, phetioObjectInitialized, and 55 more.
/Users/samreid/apache-document-root/main/molecule-polarity/js/threeatoms/ThreeAtomsScreen.ts(41,42): error TS2345: Argument of type 'TModel' is not assignable to parameter of type 'ThreeAtomsModel'.
  Type 'TModel' is missing the following properties from type 'ThreeAtomsModel': triatomicMolecule, dispose, molecule, eFieldEnabledProperty, and 57 more.
/Users/samreid/apache-document-root/main/my-solar-system/js/my-solar-system-main.ts(42,5): error TS2322: Type 'IntroScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
  Types of property 'createView' are incompatible.
    Type 'CreateView<IntroModel, IntroScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
      Type 'TModel' is missing the following properties from type 'IntroModel': bodies, availableBodies, centerOfMass, systemCenteredProperty, and 32 more.
/Users/samreid/apache-document-root/main/my-solar-system/js/my-solar-system-main.ts(43,5): error TS2322: Type 'LabScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
  Types of property 'createView' are incompatible.
    Type 'CreateView<LabModel, LabScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
      Type 'TModel' is missing the following properties from type 'LabModel': modeMap, modeSetter, setModesToMap, bodies, and 35 more.
/Users/samreid/apache-document-root/main/my-solar-system/js/my-solar-system-main.ts(44,5): error TS2322: Type 'KeplersLawsScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
  Types of property 'createView' are incompatible.
    Type 'CreateView<KeplersLawsModel, KeplersLawsScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
      Type 'TModel' is missing the following properties from type 'KeplersLawsModel': selectedLawProperty, alwaysCircularProperty, isFirstLawProperty, isSecondLawProperty, and 57 more.
/Users/samreid/apache-document-root/main/natural-selection/js/intro/IntroScreen.ts(41,37): error TS2345: Argument of type 'TModel' is not assignable to parameter of type 'IntroModel'.
  Type 'TModel' is missing the following properties from type 'IntroModel': modelViewTransform, simulationModeProperty, isPlayingProperty, timeSpeedProperty, and 17 more.
/Users/samreid/apache-document-root/main/natural-selection/js/lab/LabScreen.ts(47,35): error TS2345: Argument of type 'TModel' is not assignable to parameter of type 'LabModel'.
  Type 'TModel' is missing the following properties from type 'LabModel': modelViewTransform, simulationModeProperty, isPlayingProperty, timeSpeedProperty, and 17 more.
/Users/samreid/apache-document-root/main/number-compare/js/common/view/NumberComparePreferencesNode.ts(21,85): error TS2345: Argument of type 'typeof CompareScreen' is not assignable to parameter of type 'new (...args: any[]) => Screen<TModel, ScreenView>'.
  Types of construct signatures are incompatible.
    Type 'new (tandem: Tandem) => CompareScreen' is not assignable to type 'new (...args: any[]) => Screen<TModel, ScreenView>'.
      Construct signature return types 'CompareScreen' and 'Screen<TModel, ScreenView>' are incompatible.
        The types of 'createView' are incompatible between these types.
          Type 'CreateView<CompareModel, CompareScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
            Type 'TModel' is missing the following properties from type 'CompareModel': sumRange, countingTypeProperty, comparisonSignsAndTextVisibleProperty, leftPlayArea, and 4 more.
/Users/samreid/apache-document-root/main/number-compare/js/number-compare-main.ts(51,59): error TS2345: Argument of type 'typeof CompareScreen' is not assignable to parameter of type 'new (...args: any[]) => Screen<TModel, ScreenView>'.
/Users/samreid/apache-document-root/main/number-compare/js/number-compare-main.ts(68,5): error TS2322: Type 'CompareScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
/Users/samreid/apache-document-root/main/number-compare/js/number-compare-main.ts(69,5): error TS2322: Type 'LabScreen<NumberComparePreferences>' is not assignable to type 'Screen<TModel, ScreenView>'.
  Types of property 'createView' are incompatible.
    Type 'CreateView<LabModel, LabScreenView<NumberSuiteCommonPreferences>>' is not assignable to type 'CreateView<TModel, ScreenView>'.
/Users/samreid/apache-document-root/main/number-play/js/common/view/NumberPlayPreferencesNode.ts(23,64): error TS2345: Argument of type 'typeof NumberPlayGameScreen' is not assignable to parameter of type 'new (...args: any[]) => Screen<TModel, ScreenView>'.
  Types of construct signatures are incompatible.
    Type 'new (tandem: Tandem) => NumberPlayGameScreen' is not assignable to type 'new (...args: any[]) => Screen<TModel, ScreenView>'.
      Construct signature return types 'NumberPlayGameScreen' and 'Screen<TModel, ScreenView>' are incompatible.
        The types of 'createView' are incompatible between these types.
          Type 'CreateView<NumberPlayGameModel, NumberPlayGameScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
            Type 'TModel' is missing the following properties from type 'NumberPlayGameModel': subitizeLevels, countingLevels, levels, levelProperty, dispose
/Users/samreid/apache-document-root/main/number-play/js/common/view/NumberPlayPreferencesNode.ts(27,85): error TS2345: Argument of type 'typeof TenScreen' is not assignable to parameter of type 'new (...args: any[]) => Screen<TModel, ScreenView>'.
  Types of construct signatures are incompatible.
    Type 'new (tandem: Tandem) => TenScreen' is not assignable to type 'new (...args: any[]) => Screen<TModel, ScreenView>'.
      Construct signature return types 'TenScreen' and 'Screen<TModel, ScreenView>' are incompatible.
        The types of 'createView' are incompatible between these types.
          Type 'CreateView<TenModel, TenScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
            Type 'TModel' is missing the following properties from type 'TenModel': dispose, sumRange, currentNumberProperty, onesPlayArea, and 7 more.
/Users/samreid/apache-document-root/main/number-play/js/common/view/NumberPlayPreferencesNode.ts(28,85): error TS2345: Argument of type 'typeof TwentyScreen' is not assignable to parameter of type 'new (...args: any[]) => Screen<TModel, ScreenView>'.
  Types of construct signatures are incompatible.
    Type 'new (tandem: Tandem) => TwentyScreen' is not assignable to type 'new (...args: any[]) => Screen<TModel, ScreenView>'.
      Construct signature return types 'TwentyScreen' and 'Screen<TModel, ScreenView>' are incompatible.
        The types of 'createView' are incompatible between these types.
          Type 'CreateView<TwentyModel, NumberPlayScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
            Type 'TModel' is missing the following properties from type 'TwentyModel': dispose, sumRange, currentNumberProperty, onesPlayArea, and 7 more.
/Users/samreid/apache-document-root/main/number-play/js/number-play-main.ts(52,59): error TS2345: Argument of type 'typeof TenScreen' is not assignable to parameter of type 'new (...args: any[]) => Screen<TModel, ScreenView>'.
/Users/samreid/apache-document-root/main/number-play/js/number-play-main.ts(52,122): error TS2345: Argument of type 'typeof TwentyScreen' is not assignable to parameter of type 'new (...args: any[]) => Screen<TModel, ScreenView>'.
/Users/samreid/apache-document-root/main/number-play/js/number-play-main.ts(69,5): error TS2322: Type 'TenScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
/Users/samreid/apache-document-root/main/number-play/js/number-play-main.ts(70,5): error TS2322: Type 'TwentyScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
/Users/samreid/apache-document-root/main/number-play/js/number-play-main.ts(71,5): error TS2322: Type 'NumberPlayGameScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
/Users/samreid/apache-document-root/main/number-play/js/number-play-main.ts(72,5): error TS2322: Type 'LabScreen<NumberPlayPreferences>' is not assignable to type 'Screen<TModel, ScreenView>'.
  Types of property 'createView' are incompatible.
    Type 'CreateView<LabModel, LabScreenView<NumberSuiteCommonPreferences>>' is not assignable to type 'CreateView<TModel, ScreenView>'.
/Users/samreid/apache-document-root/main/number-suite-common/js/common/view/NumberSuiteCommonPreferencesNode.ts(48,64): error TS2345: Argument of type 'typeof LabScreen' is not assignable to parameter of type 'new (...args: any[]) => Screen<TModel, ScreenView>'.
  Types of construct signatures are incompatible.
    Type 'new <T extends NumberSuiteCommonPreferences>(symbolTypes: SymbolType[], preferences: T, tandem: Tandem) => LabScreen<T>' is not assignable to type 'new (...args: any[]) => Screen<TModel, ScreenView>'.
      Construct signature return types 'LabScreen<any>' and 'Screen<TModel, ScreenView>' are incompatible.
        The types of 'createView' are incompatible between these types.
          Type 'CreateView<LabModel, LabScreenView<NumberSuiteCommonPreferences>>' is not assignable to type 'CreateView<TModel, ScreenView>'.
            Type 'TModel' is missing the following properties from type 'LabModel': tenFrames, onesPlayArea, dogPlayArea, applePlayArea, and 4 more.
/Users/samreid/apache-document-root/main/ph-scale-basics/js/ph-scale-basics-main.ts(30,87): error TS2345: Argument of type 'MacroScreen[]' is not assignable to parameter of type 'Screen<TModel, ScreenView>[]'.
  Type 'MacroScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
/Users/samreid/apache-document-root/main/ph-scale/js/ph-scale-main.ts(32,74): error TS2345: Argument of type '(MacroScreen | MicroScreen | MySolutionScreen)[]' is not assignable to parameter of type 'Screen<TModel, ScreenView>[]'.
  Type 'MacroScreen | MicroScreen | MySolutionScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
    Type 'MacroScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
      Types of property 'createView' are incompatible.
        Type 'CreateView<MacroModel, MacroScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
          Type 'TModel' is missing the following properties from type 'MacroModel': pHMeter, solutes, beaker, dropper, and 10 more.
/Users/samreid/apache-document-root/main/quadrilateral/js/quadrilateral-main.ts(81,60): error TS2322: Type 'QuadrilateralScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
  Types of property 'createView' are incompatible.
    Type 'CreateView<QuadrilateralModel, QuadrilateralScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
      Type 'TModel' is missing the following properties from type 'QuadrilateralModel': visibilityModel, optionsModel, tangibleConnectionModel, resetNotInProgressProperty, and 15 more.
/Users/samreid/apache-document-root/main/ratio-and-proportion/js/ratio-and-proportion-main.ts(35,5): error TS2322: Type 'DiscoverScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
  Types of property 'createView' are incompatible.
    Type 'CreateView<RAPModel, DiscoverScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
      Type 'TModel' is missing the following properties from type 'RAPModel': ratio, targetRatioProperty, unclampedFitnessProperty, ratioFitnessProperty, and 9 more.
/Users/samreid/apache-document-root/main/ratio-and-proportion/js/ratio-and-proportion-main.ts(36,5): error TS2322: Type 'CreateScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
  Types of property 'createView' are incompatible.
    Type 'CreateView<RAPModel, CreateScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
      Type 'TModel' is not assignable to type 'RAPModel'.
/Users/samreid/apache-document-root/main/simula-rasa/js/simula-rasa-main.ts(41,45): error TS2345: Argument of type 'SimulaRasaScreen[]' is not assignable to parameter of type 'Screen<TModel, ScreenView>[]'.
  Type 'SimulaRasaScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
    Types of property 'createView' are incompatible.
      Type 'CreateView<SimulaRasaModel, SimulaRasaScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
        Type 'TModel' is not assignable to type 'SimulaRasaModel'.
          Types of property 'step' are incompatible.
            Type '((dt: number) => void) | undefined' is not assignable to type '(dt: number) => void'.
              Type 'undefined' is not assignable to type '(dt: number) => void'.
/Users/samreid/apache-document-root/main/sound/js/sound-main.ts(34,5): error TS2322: Type 'SoundScreen<IntroModel>' is not assignable to type 'Screen<TModel, ScreenView>'.
  Types of property 'createView' are incompatible.
    Type 'CreateView<IntroModel, SoundScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
      Type 'TModel' is missing the following properties from type 'IntroModel': audioControlSettingProperty, listenerPositionProperty, isAudioEnabledProperty, modelToLatticeTransform, and 25 more.
/Users/samreid/apache-document-root/main/sound/js/sound-main.ts(35,5): error TS2322: Type 'SoundScreen<MeasureModel>' is not assignable to type 'Screen<TModel, ScreenView>'.
  Types of property 'createView' are incompatible.
    Type 'CreateView<MeasureModel, SoundScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
      Type 'TModel' is missing the following properties from type 'MeasureModel': stopwatch, rulerPositionProperty, isAudioEnabledProperty, modelToLatticeTransform, and 25 more.
/Users/samreid/apache-document-root/main/sound/js/sound-main.ts(36,5): error TS2322: Type 'SoundScreen<TwoSourceModel>' is not assignable to type 'Screen<TModel, ScreenView>'.
  Types of property 'createView' are incompatible.
    Type 'CreateView<TwoSourceModel, SoundScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
      Type 'TModel' is missing the following properties from type 'TwoSourceModel': listenerPositionProperty, speaker2PositionProperty, isAudioEnabledProperty, modelToLatticeTransform, and 25 more.
/Users/samreid/apache-document-root/main/sound/js/sound-main.ts(37,5): error TS2322: Type 'SoundScreen<ReflectionModel>' is not assignable to type 'Screen<TModel, ScreenView>'.
  Types of property 'createView' are incompatible.
    Type 'CreateView<ReflectionModel, SoundScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
      Type 'TModel' is missing the following properties from type 'ReflectionModel': wallPositionXProperty, wallAngleProperty, soundModeProperty, isAudioEnabledProperty, and 26 more.
/Users/samreid/apache-document-root/main/sound/js/sound-main.ts(38,5): error TS2322: Type 'SoundScreen<PressureModel>' is not assignable to type 'Screen<TModel, ScreenView>'.
  Types of property 'createView' are incompatible.
    Type 'CreateView<PressureModel, SoundScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
      Type 'TModel' is missing the following properties from type 'PressureModel': pressureProperty, audioControlSettingProperty, listenerPositionProperty, isAudioEnabledProperty, and 26 more.
/Users/samreid/apache-document-root/main/tambo/js/tambo-main.ts(80,5): error TS2322: Type 'Screen<SimLikeComponentsModel, SimLikeComponentsScreenView>' is not assignable to type 'Screen<TModel, ScreenView>'.
  Types of property 'createView' are incompatible.
    Type 'CreateView<SimLikeComponentsModel, SimLikeComponentsScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
      Type 'TModel' is not assignable to type 'SimLikeComponentsModel'.
/Users/samreid/apache-document-root/main/tambo/js/tambo-main.ts(96,5): error TS2322: Type 'Screen<UIComponentsModel, UIComponentsScreenView>' is not assignable to type 'Screen<TModel, ScreenView>'.
  Types of property 'createView' are incompatible.
    Type 'CreateView<UIComponentsModel, UIComponentsScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
      Type 'TModel' is not assignable to type 'UIComponentsModel'.
/Users/samreid/apache-document-root/main/wilder/js/wilder-main.ts(29,53): error TS2322: Type 'WilderScreen' is not assignable to type 'Screen<TModel, ScreenView>'.
  Types of property 'createView' are incompatible.
    Type 'CreateView<WilderModel, WilderScreenView>' is not assignable to type 'CreateView<TModel, ScreenView>'.
      Type 'TModel' is missing the following properties from type 'WilderModel': wilderOptionsPatterns, wilderEnumerationPatterns
101 errors in 6405ms

So I feel this is more of a collaboration issue. Please reach out to me on slack to schedule a time if you want to work on it together.

@samreid samreid assigned pixelzoom and unassigned samreid Feb 14, 2023
@pixelzoom
Copy link
Contributor Author

Unlikely that I'll be able to join you on this until March. But I'll let you know if that changes.

@pixelzoom
Copy link
Contributor Author

Thinking about this more... I did report this problem because I'm hitting it repeatedly, it's a problem in a foundational class, and it seems solvable. So I don't agree that masking the problem with IntentionalAny is "in line with our philosophy about getting added value from TypeScript". That said... I was not involved in the converson of Screen to TypeScript, I'm not responsible dev for joist, and I really don't have time to assist with this. So assigning back to @samreid (who did do the TypeScript conversion). If you need assistance or prioritization, consult with @kathy-phet.

@pixelzoom pixelzoom assigned samreid and unassigned pixelzoom Feb 15, 2023
pixelzoom added a commit to phetsims/graphing-slope-intercept that referenced this issue Feb 15, 2023
pixelzoom added a commit to phetsims/natural-selection that referenced this issue Feb 15, 2023
pixelzoom added a commit to phetsims/molecule-polarity that referenced this issue Feb 15, 2023
pixelzoom added a commit to phetsims/hookes-law that referenced this issue Feb 15, 2023
pixelzoom added a commit to phetsims/circuit-construction-kit-common that referenced this issue Feb 15, 2023
@pixelzoom
Copy link
Contributor Author

pixelzoom commented Feb 15, 2023

In the above commits, I added missing implements TModel and missing Screen<...> to all TypeScript sims. No guarantee that I didn't miss some. But sims should be in a better place for changes to Screen.

@samreid
Copy link
Member

samreid commented Feb 15, 2023

I saw more notes about this problem in #783 (comment)

@samreid
Copy link
Member

samreid commented Feb 15, 2023

After @pixelzoom commits above, I tried class Screen<M extends TModel = TModel again and saw 97 type errors. Most of them are nontrivial, like this one in Beer's Law Lab:

image

Here's one I have no idea how to solve in NavigationBar:

image

Anyways, there are 95 other errors like that. I don't feel I have the expertise to develop a good solution here. We could reach out to #dev-public and see if someone else wants to attempt it? Or maybe even better to schedule it for the next sprint. But my suspicion is that we will conclude "it is not worth the time and baggage to add this level of type parametrization in Screen". But I would be happy to be wrong about that.

@samreid
Copy link
Member

samreid commented Feb 15, 2023

I wrote to slack #dev-public:

Anybody want to volunteer to work on improving the type parameterization for Screen.ts? It’s listed in #886. If nobody volunteers, we can promote it as a next-sprint goal maybe.

I also listed it as a "proposed dev activity" in the 2023 iterations project board: https://github.com/orgs/phetsims/projects/65/views/7

@samreid samreid removed their assignment Feb 15, 2023
@samreid
Copy link
Member

samreid commented May 1, 2023

Maybe something like this patch "AnyScreen" would be good?

Subject: [PATCH] Remove completed TODO, see https://github.com/phetsims/center-and-variability/issues/45
---
Index: main/balancing-chemical-equations/js/game/GameScreen.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/main/balancing-chemical-equations/js/game/GameScreen.ts b/main/balancing-chemical-equations/js/game/GameScreen.ts
--- a/main/balancing-chemical-equations/js/game/GameScreen.ts	(revision f140cc1a1a9c553d91586ccf85c63633776c8268)
+++ b/main/balancing-chemical-equations/js/game/GameScreen.ts	(date 1682946482460)
@@ -19,7 +19,7 @@
 import GameModel from './model/GameModel.js';
 import GameScreenView from './view/GameScreenView.js';
 
-export default class GameScreen extends Screen {
+export default class GameScreen extends Screen<GameModel, GameScreenView> {
 
   public constructor( tandem: Tandem ) {
 
Index: main/joist/js/demo/DialogsScreenView.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/main/joist/js/demo/DialogsScreenView.ts b/main/joist/js/demo/DialogsScreenView.ts
--- a/main/joist/js/demo/DialogsScreenView.ts	(revision a88f873fd63c66c0e1300f2be0b96fbb614a9397)
+++ b/main/joist/js/demo/DialogsScreenView.ts	(date 1682946518316)
@@ -14,7 +14,7 @@
 import joist from '../joist.js';
 import KeyboardHelpButton from '../KeyboardHelpButton.js';
 import ScreenView, { ScreenViewOptions } from '../ScreenView.js';
-import Screen from '../Screen.js';
+import Screen, { AnyScreen } from '../Screen.js';
 import Sim from '../Sim.js';
 import NavigationBarPreferencesButton from '../preferences/NavigationBarPreferencesButton.js';
 import PreferencesModel from '../preferences/PreferencesModel.js';
@@ -29,7 +29,7 @@
 
     const keyboardHelpDialogContent = new BasicActionsKeyboardHelpSection();
 
-    const fakeScreen = { createKeyboardHelpNode: () => keyboardHelpDialogContent, tandem: Tandem.OPTIONAL } as unknown as Screen;
+    const fakeScreen = { createKeyboardHelpNode: () => keyboardHelpDialogContent, tandem: Tandem.OPTIONAL } as unknown as AnyScreen;
     const keyboardHelpButton = new KeyboardHelpButton(
       [ fakeScreen ],
       new Property( fakeScreen ),
Index: main/number-compare/js/common/view/numberCompareUtteranceQueue.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/main/number-compare/js/common/view/numberCompareUtteranceQueue.ts b/main/number-compare/js/common/view/numberCompareUtteranceQueue.ts
--- a/main/number-compare/js/common/view/numberCompareUtteranceQueue.ts	(revision 9761d4fc4df82ff32f85f765a42d48d58df93909)
+++ b/main/number-compare/js/common/view/numberCompareUtteranceQueue.ts	(date 1682946547954)
@@ -17,7 +17,7 @@
 import numberComparePreferences from '../model/numberComparePreferences.js';
 import Property from '../../../../axon/js/Property.js';
 import TReadOnlyProperty from '../../../../axon/js/TReadOnlyProperty.js';
-import Screen from '../../../../joist/js/Screen.js';
+import Screen, { AnyScreen } from '../../../../joist/js/Screen.js';
 
 class NumberCompareUtteranceQueue extends NumberSuiteCommonUtteranceQueue {
 
@@ -41,7 +41,7 @@
    * to use for a given screen that the user is viewing. This is needed because selectedScreenProperty doesn't exist
    * yet during the creation of this singleton.
    */
-  public initialize( selectedScreenProperty: TReadOnlyProperty<Screen> ): void {
+  public initialize( selectedScreenProperty: TReadOnlyProperty<AnyScreen> ): void {
 
     const speechDataProperty = new DerivedProperty(
       [ this.compareScreenSpeechDataProperty, selectedScreenProperty ], ( compareScreenSpeechData, selectedScreen ) => {
Index: main/joist/js/selectScreens.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/main/joist/js/selectScreens.ts b/main/joist/js/selectScreens.ts
--- a/main/joist/js/selectScreens.ts	(revision a88f873fd63c66c0e1300f2be0b96fbb614a9397)
+++ b/main/joist/js/selectScreens.ts	(date 1682945915838)
@@ -1,13 +1,13 @@
 // Copyright 2020-2022, University of Colorado Boulder
 import joist from './joist.js';
 import HomeScreen from './HomeScreen.js';
-import Screen from './Screen.js';
+import { AnyScreen } from './Screen.js';
 
 export type ScreenReturnType = {
   homeScreen: HomeScreen | null;
-  initialScreen: Screen;
-  selectedSimScreens: Screen[];
-  screens: Screen[];
+  initialScreen: AnyScreen;
+  selectedSimScreens: AnyScreen[];
+  screens: AnyScreen[];
   allScreensCreated: boolean;
 };
 
@@ -33,15 +33,15 @@
  * @returns - duck-typed for tests
  * @throws Error if incompatible data is provided
  */
-export default function selectScreens( allSimScreens: Screen[],
+export default function selectScreens( allSimScreens: AnyScreen[],
                                        homeScreenQueryParameter: boolean,
                                        homeScreenQueryParameterProvided: boolean,
                                        initialScreenIndex: number,
                                        initialScreenQueryParameterProvided: boolean,
                                        screensQueryParameter: number[],
                                        screensQueryParameterProvided: boolean,
-                                       setupScreens: ( screens: Screen[] ) => void,
-                                       createHomeScreen: ( screens: Screen[] ) => HomeScreen ): ScreenReturnType {
+                                       setupScreens: ( screens: AnyScreen[] ) => void,
+                                       createHomeScreen: ( screens: AnyScreen[] ) => HomeScreen ): ScreenReturnType {
 
   if ( allSimScreens.length === 1 && homeScreenQueryParameterProvided && homeScreenQueryParameter ) {
     const errorMessage = 'cannot specify homeScreen=true for single-screen sims';
Index: main/number-play/js/common/view/numberPlayUtteranceQueue.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/main/number-play/js/common/view/numberPlayUtteranceQueue.ts b/main/number-play/js/common/view/numberPlayUtteranceQueue.ts
--- a/main/number-play/js/common/view/numberPlayUtteranceQueue.ts	(revision d7c72aec4c1b161c38745e531fdbb4e13c2a5549)
+++ b/main/number-play/js/common/view/numberPlayUtteranceQueue.ts	(date 1682946560374)
@@ -16,7 +16,7 @@
 import numberPlayPreferences from '../model/numberPlayPreferences.js';
 import TProperty from '../../../../axon/js/TProperty.js';
 import DerivedProperty from '../../../../axon/js/DerivedProperty.js';
-import Screen from '../../../../joist/js/Screen.js';
+import Screen, { AnyScreen } from '../../../../joist/js/Screen.js';
 import TReadOnlyProperty from '../../../../axon/js/TReadOnlyProperty.js';
 import StringProperty from '../../../../axon/js/StringProperty.js';
 
@@ -46,7 +46,7 @@
    * to use for a given screen that the user is viewing. This is needed because selectedScreenProperty doesn't exist
    * yet during the creation of this singleton.
    */
-  public initialize( selectedScreenProperty: TReadOnlyProperty<Screen> ): void {
+  public initialize( selectedScreenProperty: TReadOnlyProperty<AnyScreen> ): void {
 
     const speechDataProperty = new DerivedProperty(
       [ this.tenScreenSpeechDataProperty, this.twentyScreenSpeechDataProperty, selectedScreenProperty ],
Index: main/joist/js/KeyboardHelpButton.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/main/joist/js/KeyboardHelpButton.ts b/main/joist/js/KeyboardHelpButton.ts
--- a/main/joist/js/KeyboardHelpButton.ts	(revision a88f873fd63c66c0e1300f2be0b96fbb614a9397)
+++ b/main/joist/js/KeyboardHelpButton.ts	(date 1682945791859)
@@ -18,7 +18,7 @@
 import JoistButton, { JoistButtonOptions } from './JoistButton.js';
 import JoistStrings from './JoistStrings.js';
 import KeyboardHelpDialog from './KeyboardHelpDialog.js';
-import Screen from './Screen.js';
+import { AnyScreen } from './Screen.js';
 import PickRequired from '../../phet-core/js/types/PickRequired.js';
 import TReadOnlyProperty from '../../axon/js/TReadOnlyProperty.js';
 
@@ -31,7 +31,7 @@
 
 class KeyboardHelpButton extends JoistButton {
 
-  public constructor( screens: Screen[], screenProperty: Property<Screen>,
+  public constructor( screens: AnyScreen[], screenProperty: Property<AnyScreen>,
                       backgroundColorProperty: TReadOnlyProperty<Color>,
                       providedOptions: KeyboardHelpButtonOptions ) {
 
Index: main/joist/js/KeyboardHelpDialog.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/main/joist/js/KeyboardHelpDialog.ts b/main/joist/js/KeyboardHelpDialog.ts
--- a/main/joist/js/KeyboardHelpDialog.ts	(revision a88f873fd63c66c0e1300f2be0b96fbb614a9397)
+++ b/main/joist/js/KeyboardHelpDialog.ts	(date 1682945814959)
@@ -18,7 +18,7 @@
 import Dialog, { DialogOptions } from '../../sun/js/Dialog.js';
 import joist from './joist.js';
 import JoistStrings from './JoistStrings.js';
-import Screen from './Screen.js';
+import { AnyScreen } from './Screen.js';
 
 // constants
 const TITLE_MAX_WIDTH = 670;
@@ -32,7 +32,7 @@
 export default class KeyboardHelpDialog extends Dialog {
   private readonly disposeKeyboardHelpDialog: () => void;
 
-  public constructor( screens: Screen[], screenProperty: Property<Screen>, providedOptions?: KeyboardHelpDialogOptions ) {
+  public constructor( screens: AnyScreen[], screenProperty: Property<AnyScreen>, providedOptions?: KeyboardHelpDialogOptions ) {
 
     const options = optionize<KeyboardHelpDialogOptions, SelfOptions, DialogOptions>()( {
       titleAlign: 'center',
Index: main/joist/js/HomeScreenModel.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/main/joist/js/HomeScreenModel.ts b/main/joist/js/HomeScreenModel.ts
--- a/main/joist/js/HomeScreenModel.ts	(revision a88f873fd63c66c0e1300f2be0b96fbb614a9397)
+++ b/main/joist/js/HomeScreenModel.ts	(date 1682945738255)
@@ -13,14 +13,14 @@
 import IntentionalAny from '../../phet-core/js/types/IntentionalAny.js';
 import Tandem from '../../tandem/js/Tandem.js';
 import joist from './joist.js';
-import Screen from './Screen.js';
+import Screen, { AnyScreen } from './Screen.js';
 import TModel from './TModel.js';
 
 class HomeScreenModel implements TModel {
-  public simScreens: Screen[]; // screens in the simulations that are not the HomeScreen
-  public screenProperty: Property<Screen>;
-  public selectedScreenProperty: Property<Screen>;
-  public readonly activeSimScreensProperty: ReadOnlyProperty<Screen[]>;
+  public simScreens: AnyScreen[]; // screens in the simulations that are not the HomeScreen
+  public screenProperty: Property<AnyScreen>;
+  public selectedScreenProperty: Property<AnyScreen>;
+  public readonly activeSimScreensProperty: ReadOnlyProperty<AnyScreen[]>;
 
   /**
    * @param screenProperty - the screen that is displayed to the user in the main area above the
@@ -28,7 +28,7 @@
    * @param simScreens
    * @param tandem
    */
-  public constructor( screenProperty: Property<Screen<IntentionalAny, IntentionalAny>>, simScreens: Screen<IntentionalAny, IntentionalAny>[], activeSimScreensProperty: ReadOnlyProperty<Screen[]>, tandem: Tandem ) {
+  public constructor( screenProperty: Property<Screen<IntentionalAny, IntentionalAny>>, simScreens: Screen<IntentionalAny, IntentionalAny>[], activeSimScreensProperty: ReadOnlyProperty<AnyScreen[]>, tandem: Tandem ) {
 
     this.simScreens = simScreens;
     this.screenProperty = screenProperty;
Index: main/joist/js/Sim.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/main/joist/js/Sim.ts b/main/joist/js/Sim.ts
--- a/main/joist/js/Sim.ts	(revision a88f873fd63c66c0e1300f2be0b96fbb614a9397)
+++ b/main/joist/js/Sim.ts	(date 1682945952896)
@@ -50,7 +50,7 @@
 import PreferencesModel from './preferences/PreferencesModel.js';
 import Profiler from './Profiler.js';
 import QueryParametersWarningDialog from './QueryParametersWarningDialog.js';
-import Screen from './Screen.js';
+import Screen, { AnyScreen } from './Screen.js';
 import ScreenSelectionSoundGenerator from './ScreenSelectionSoundGenerator.js';
 import ScreenshotGenerator from './ScreenshotGenerator.js';
 import selectScreens from './selectScreens.js';
@@ -146,20 +146,20 @@
   public readonly stepSimulationAction: PhetioAction<[ number ]>;
 
   // the ordered list of sim-specific screens that appear in this runtime of the sim
-  public readonly simScreens: Screen[];
+  public readonly simScreens: AnyScreen[];
 
   // all screens that appear in the runtime of this sim, with the homeScreen first if it was created
-  public readonly screens: Screen[];
+  public readonly screens: AnyScreen[];
 
   // the displayed name in the sim. This depends on what screens are shown this runtime (effected by query parameters).
   public readonly displayedSimNameProperty: TReadOnlyProperty<string>;
-  public readonly selectedScreenProperty: Property<Screen>;
+  public readonly selectedScreenProperty: Property<AnyScreen>;
 
   // true if all possible screens are present (order-independent)
   private readonly allScreensCreated: boolean;
 
   private availableScreensProperty!: Property<number[]>;
-  public activeSimScreensProperty!: ReadOnlyProperty<Screen[]>;
+  public activeSimScreensProperty!: ReadOnlyProperty<AnyScreen[]>;
 
   // When the sim is active, scenery processes inputs and stepSimulation(dt) runs from the system clock.
   // Set to false for when the sim will be paused.
@@ -256,7 +256,7 @@
    * @param allSimScreens - the possible screens for the sim in order of declaration (does not include the home screen)
    * @param [providedOptions] - see below for options
    */
-  public constructor( simNameProperty: TReadOnlyProperty<string>, allSimScreens: Screen[], providedOptions?: SimOptions ) {
+  public constructor( simNameProperty: TReadOnlyProperty<string>, allSimScreens: AnyScreen[], providedOptions?: SimOptions ) {
 
     window.phetSplashScreenDownloadComplete();
 
@@ -507,7 +507,7 @@
     this.screens = screenData.screens;
     this.allScreensCreated = screenData.allScreensCreated;
 
-    this.selectedScreenProperty = new Property<Screen>( screenData.initialScreen, {
+    this.selectedScreenProperty = new Property<AnyScreen>( screenData.initialScreen, {
       tandem: screensTandem.createTandem( 'selectedScreenProperty' ),
       phetioFeatured: true,
       phetioDocumentation: 'Determines which screen is selected in the simulation',
@@ -728,7 +728,7 @@
     animationFrameTimer.runOnNextTick( () => phet.joist.display.updateDisplay() );
   }
 
-  private finishInit( screens: Screen[] ): void {
+  private finishInit( screens: AnyScreen[] ): void {
 
     _.each( screens, screen => {
       screen.view.layerSplit = true;
Index: main/beers-law-lab/js/common/view/BLLSim.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/main/beers-law-lab/js/common/view/BLLSim.ts b/main/beers-law-lab/js/common/view/BLLSim.ts
--- a/main/beers-law-lab/js/common/view/BLLSim.ts	(revision 93d4a82f5804d83f550ade53bdbb84c95e109044)
+++ b/main/beers-law-lab/js/common/view/BLLSim.ts	(date 1682946503419)
@@ -8,7 +8,7 @@
 
 import TReadOnlyProperty from '../../../../axon/js/TReadOnlyProperty.js';
 import Sim, { SimOptions } from '../../../../joist/js/Sim.js';
-import Screen from '../../../../joist/js/Screen.js';
+import { AnyScreen } from '../../../../joist/js/Screen.js';
 import optionize, { EmptySelfOptions } from '../../../../phet-core/js/optionize.js';
 import PickOptional from '../../../../phet-core/js/types/PickOptional.js';
 import beersLawLab from '../../beersLawLab.js';
@@ -23,7 +23,7 @@
 
 export default class BLLSim extends Sim {
 
-  public constructor( simNameProperty: TReadOnlyProperty<string>, screens: Screen[], providedOptions?: BLLSimOptions ) {
+  public constructor( simNameProperty: TReadOnlyProperty<string>, screens: AnyScreen[], providedOptions?: BLLSimOptions ) {
 
     const options = optionize<BLLSimOptions, SelfOptions, SimOptions>()( {
 
Index: main/joist/js/NavigationBarScreenButton.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/main/joist/js/NavigationBarScreenButton.ts b/main/joist/js/NavigationBarScreenButton.ts
--- a/main/joist/js/NavigationBarScreenButton.ts	(revision a88f873fd63c66c0e1300f2be0b96fbb614a9397)
+++ b/main/joist/js/NavigationBarScreenButton.ts	(date 1682945864928)
@@ -21,7 +21,7 @@
 import PushButtonModel from '../../sun/js/buttons/PushButtonModel.js';
 import HighlightNode from './HighlightNode.js';
 import joist from './joist.js';
-import Screen from './Screen.js';
+import { AnyScreen } from './Screen.js';
 import PickRequired from '../../phet-core/js/types/PickRequired.js';
 
 // constants
@@ -37,7 +37,7 @@
 class NavigationBarScreenButton extends Voicing( Node ) {
   private readonly buttonModel: PushButtonModel;
 
-  public readonly screen: Screen;
+  public readonly screen: AnyScreen;
 
   /**
    * @param navigationBarFillProperty - the color of the navbar, as a string.
@@ -47,8 +47,8 @@
    * @param navBarHeight
    * @param [providedOptions]
    */
-  public constructor( navigationBarFillProperty: TReadOnlyProperty<Color>, screenProperty: Property<Screen>,
-                      screen: Screen, simScreenIndex: number, navBarHeight: number,
+  public constructor( navigationBarFillProperty: TReadOnlyProperty<Color>, screenProperty: Property<AnyScreen>,
+                      screen: AnyScreen, simScreenIndex: number, navBarHeight: number,
                       providedOptions: NavigationBarScreenButtonOptions ) {
 
     assert && assert( screen.nameProperty.value, `name is required for screen ${simScreenIndex}` );
Index: main/joist/js/NavigationBar.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/main/joist/js/NavigationBar.ts b/main/joist/js/NavigationBar.ts
--- a/main/joist/js/NavigationBar.ts	(revision a88f873fd63c66c0e1300f2be0b96fbb614a9397)
+++ b/main/joist/js/NavigationBar.ts	(date 1682945711853)
@@ -40,7 +40,7 @@
 import Sim from './Sim.js';
 import ReadOnlyProperty from '../../axon/js/ReadOnlyProperty.js';
 import Bounds2 from '../../dot/js/Bounds2.js';
-import Screen from './Screen.js';
+import Screen, { AnyScreen } from './Screen.js';
 import BooleanProperty from '../../axon/js/BooleanProperty.js';
 
 // constants
@@ -246,7 +246,7 @@
       } )!.width );
       const maxScreenButtonHeight = _.maxBy( screenButtons, button => button.height )!.height;
 
-      const screenButtonMap = new Map<Screen, Node>();
+      const screenButtonMap = new Map<AnyScreen, Node>();
       screenButtons.forEach( screenButton => {
         screenButtonMap.set( screenButton.screen, new AlignBox( screenButton, {
           excludeInvisibleChildrenFromBounds: true,
Index: main/joist/js/ScreenSelectionSoundGenerator.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/main/joist/js/ScreenSelectionSoundGenerator.ts b/main/joist/js/ScreenSelectionSoundGenerator.ts
--- a/main/joist/js/ScreenSelectionSoundGenerator.ts	(revision a88f873fd63c66c0e1300f2be0b96fbb614a9397)
+++ b/main/joist/js/ScreenSelectionSoundGenerator.ts	(date 1682945887269)
@@ -11,12 +11,12 @@
 import SoundClip, { SoundClipOptions } from '../../tambo/js/sound-generators/SoundClip.js';
 import screenSelection_mp3 from '../sounds/screenSelection_mp3.js';
 import joist from './joist.js';
-import Screen from './Screen.js';
+import { AnyScreen } from './Screen.js';
 import HomeScreen from './HomeScreen.js';
 
 class ScreenSelectionSoundGenerator extends SoundClip {
 
-  public constructor( screenProperty: ReadOnlyProperty<Screen>, homeScreen: HomeScreen | null, options?: SoundClipOptions ) {
+  public constructor( screenProperty: ReadOnlyProperty<AnyScreen>, homeScreen: HomeScreen | null, options?: SoundClipOptions ) {
 
     super( screenSelection_mp3, options );
 
Index: main/joist/js/toolbar/Toolbar.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/main/joist/js/toolbar/Toolbar.ts b/main/joist/js/toolbar/Toolbar.ts
--- a/main/joist/js/toolbar/Toolbar.ts	(revision a88f873fd63c66c0e1300f2be0b96fbb614a9397)
+++ b/main/joist/js/toolbar/Toolbar.ts	(date 1682945992734)
@@ -31,7 +31,7 @@
 import VoicingToolbarAlertManager from './VoicingToolbarAlertManager.js';
 import VoicingToolbarItem from './VoicingToolbarItem.js';
 import LookAndFeel from '../LookAndFeel.js';
-import Screen from '../Screen.js';
+import Screen, { AnyScreen } from '../Screen.js';
 
 // constants
 const MAX_ANIMATION_SPEED = 250; // in view coordinates per second, assuming 60 fps
@@ -91,7 +91,7 @@
   private readonly contentMargin: number;
   private readonly disposeToolbar: () => void;
 
-  public constructor( enabledProperty: TReadOnlyProperty<boolean>, selectedScreenProperty: TReadOnlyProperty<Screen>,
+  public constructor( enabledProperty: TReadOnlyProperty<boolean>, selectedScreenProperty: TReadOnlyProperty<AnyScreen>,
                       lookAndFeel: LookAndFeel, providedOptions?: ToolbarOptions ) {
 
     const options = optionize<ToolbarOptions, SelfOptions, NodeOptions>()( {
Index: main/joist/js/HomeScreen.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/main/joist/js/HomeScreen.ts b/main/joist/js/HomeScreen.ts
--- a/main/joist/js/HomeScreen.ts	(revision a88f873fd63c66c0e1300f2be0b96fbb614a9397)
+++ b/main/joist/js/HomeScreen.ts	(date 1682945011801)
@@ -17,6 +17,7 @@
 import joist from './joist.js';
 import JoistStrings from './JoistStrings.js';
 import Screen, { ScreenOptions } from './Screen.js';
+import IntentionalAny from '../../phet-core/js/types/IntentionalAny.js';
 
 // constants
 const homeStringProperty = JoistStrings.a11y.homeStringProperty;
@@ -32,9 +33,9 @@
 
   public constructor(
     simNameProperty: TReadOnlyProperty<string>,
-    getScreenProperty: () => Property<Screen>,
-    simScreens: Screen[],
-    activeSimScreensProperty: ReadOnlyProperty<Screen[]>,
+    getScreenProperty: () => Property<Screen<IntentionalAny, IntentionalAny>>,
+    simScreens: Screen<IntentionalAny, IntentionalAny>[],
+    activeSimScreensProperty: ReadOnlyProperty<Screen<IntentionalAny, IntentionalAny>[]>,
     providedOptions: HomeScreenOptions
   ) {
 
Index: main/joist/js/toolbar/VoicingToolbarAlertManager.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/main/joist/js/toolbar/VoicingToolbarAlertManager.ts b/main/joist/js/toolbar/VoicingToolbarAlertManager.ts
--- a/main/joist/js/toolbar/VoicingToolbarAlertManager.ts	(revision a88f873fd63c66c0e1300f2be0b96fbb614a9397)
+++ b/main/joist/js/toolbar/VoicingToolbarAlertManager.ts	(date 1682946007972)
@@ -11,17 +11,17 @@
 import TReadOnlyProperty from '../../../axon/js/TReadOnlyProperty.js';
 import { SpeakableResolvedResponse } from '../../../utterance-queue/js/ResponsePacket.js';
 import joist from '../joist.js';
-import Screen from '../Screen.js';
+import { AnyScreen } from '../Screen.js';
 
 class VoicingToolbarAlertManager {
 
   // The active Screen for the simulation, to generate Voicing descriptions that are related to the active screen.
-  private readonly screenProperty: TReadOnlyProperty<Screen>;
+  private readonly screenProperty: TReadOnlyProperty<AnyScreen>;
 
   /**
    * @param screenProperty - indicates the active screen
    */
-  public constructor( screenProperty: TReadOnlyProperty<Screen> ) {
+  public constructor( screenProperty: TReadOnlyProperty<AnyScreen> ) {
     this.screenProperty = screenProperty;
   }
 
Index: main/phet-io-test-sim/js/phet-io-test-sim/PhetIoTestSimScreen.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/main/phet-io-test-sim/js/phet-io-test-sim/PhetIoTestSimScreen.ts b/main/phet-io-test-sim/js/phet-io-test-sim/PhetIoTestSimScreen.ts
--- a/main/phet-io-test-sim/js/phet-io-test-sim/PhetIoTestSimScreen.ts	(revision 55cabc9caeb79617f555e942312ca617bb2e7c4d)
+++ b/main/phet-io-test-sim/js/phet-io-test-sim/PhetIoTestSimScreen.ts	(date 1682946593523)
@@ -11,7 +11,7 @@
 import PhetIoTestSimScreenView from './view/PhetIoTestSimScreenView.js';
 import Tandem from '../../../tandem/js/Tandem.js';
 
-class PhetIoTestSimScreen extends Screen {
+class PhetIoTestSimScreen extends Screen<PhetIoTestSimModel, PhetIoTestSimScreenView> {
 
   public constructor( tandem: Tandem ) {
 
Index: main/joist/js/SimInfo.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/main/joist/js/SimInfo.ts b/main/joist/js/SimInfo.ts
--- a/main/joist/js/SimInfo.ts	(revision a88f873fd63c66c0e1300f2be0b96fbb614a9397)
+++ b/main/joist/js/SimInfo.ts	(date 1682945975031)
@@ -20,7 +20,7 @@
 import ObjectLiteralIO from '../../tandem/js/types/ObjectLiteralIO.js';
 import StringIO from '../../tandem/js/types/StringIO.js';
 import joist from './joist.js';
-import Screen from './Screen.js';
+import { AnyScreen } from './Screen.js';
 import packageJSON from './packageJSON.js';
 import Sim from './Sim.js';
 
@@ -110,7 +110,7 @@
     this.putInfo( 'simName', sim.simNameProperty.value );
     this.putInfo( 'simVersion', sim.version );
     this.putInfo( 'repoName', packageJSON.name );
-    this.putInfo( 'screens', sim.screens.map( ( screen: Screen ) => {
+    this.putInfo( 'screens', sim.screens.map( ( screen: AnyScreen ) => {
       const screenObject: ScreenState = {
 
         // likely null for single screen sims, so use the sim name as a default
Index: main/number-suite-common/js/common/view/NumberSuiteCommonPreferencesNode.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/main/number-suite-common/js/common/view/NumberSuiteCommonPreferencesNode.ts b/main/number-suite-common/js/common/view/NumberSuiteCommonPreferencesNode.ts
--- a/main/number-suite-common/js/common/view/NumberSuiteCommonPreferencesNode.ts	(revision 0b758f0455f7444575e254ad33bcfe62364b8352)
+++ b/main/number-suite-common/js/common/view/NumberSuiteCommonPreferencesNode.ts	(date 1682946574838)
@@ -11,7 +11,7 @@
 import optionize from '../../../../phet-core/js/optionize.js';
 import numberSuiteCommon from '../../numberSuiteCommon.js';
 import NumberSuiteCommonPreferences from '../model/NumberSuiteCommonPreferences.js';
-import Screen from '../../../../joist/js/Screen.js';
+import Screen, { AnyScreen } from '../../../../joist/js/Screen.js';
 import IntentionalAny from '../../../../phet-core/js/types/IntentionalAny.js';
 import StrictOmit from '../../../../phet-core/js/types/StrictOmit.js';
 import SecondLanguageControl from './SecondLanguageControl.js';
@@ -65,7 +65,7 @@
   /**
    * Determines whether the sim is running with a screen of the specified type.
    */
-  public static hasScreenType( constructor: new ( ...args: IntentionalAny[] ) => Screen ): boolean {
+  public static hasScreenType( constructor: new ( ...args: IntentionalAny[] ) => AnyScreen ): boolean {
     return ( _.find( phet.joist.sim.screens, screen => screen instanceof constructor ) !== undefined );
   }
 }
Index: main/joist/js/HomeScreenView.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/main/joist/js/HomeScreenView.ts b/main/joist/js/HomeScreenView.ts
--- a/main/joist/js/HomeScreenView.ts	(revision a88f873fd63c66c0e1300f2be0b96fbb614a9397)
+++ b/main/joist/js/HomeScreenView.ts	(date 1682945767576)
@@ -16,7 +16,7 @@
 import joist from './joist.js';
 import JoistStrings from './JoistStrings.js';
 import ScreenView, { ScreenViewOptions } from './ScreenView.js';
-import Screen from './Screen.js';
+import Screen, { AnyScreen } from './Screen.js';
 import HomeScreenModel from './HomeScreenModel.js';
 import Property from '../../axon/js/Property.js';
 import optionize from '../../phet-core/js/optionize.js';
@@ -35,7 +35,7 @@
 class HomeScreenView extends ScreenView {
 
   private homeScreenScreenSummaryIntroProperty!: TReadOnlyProperty<string>;
-  private selectedScreenProperty: Property<Screen>;
+  private selectedScreenProperty: Property<AnyScreen>;
   public screenButtons: HomeScreenButton[];
 
   // NOTE: In https://github.com/phetsims/joist/issues/640, we attempted to use ScreenView.DEFAULT_LAYOUT_BOUNDS here.
@@ -91,7 +91,7 @@
 
     const buttonGroupTandem = options.tandem.createTandem( 'buttonGroup' );
 
-    this.screenButtons = _.map( model.simScreens, ( screen: Screen ) => {
+    this.screenButtons = _.map( model.simScreens, ( screen: AnyScreen ) => {
 
       assert && assert( screen.nameProperty.value, `name is required for screen ${model.simScreens.indexOf( screen )}` );
       assert && assert( screen.homeScreenIcon, `homeScreenIcon is required for screen ${screen.nameProperty.value}` );
Index: main/balancing-chemical-equations/js/balancing-chemical-equations-main.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/main/balancing-chemical-equations/js/balancing-chemical-equations-main.ts b/main/balancing-chemical-equations/js/balancing-chemical-equations-main.ts
--- a/main/balancing-chemical-equations/js/balancing-chemical-equations-main.ts	(revision f140cc1a1a9c553d91586ccf85c63633776c8268)
+++ b/main/balancing-chemical-equations/js/balancing-chemical-equations-main.ts	(date 1682946467197)
@@ -13,12 +13,10 @@
 
 simLauncher.launch( () => {
 
-  const screens = [
+  const sim = new Sim( BalancingChemicalEquationsStrings[ 'balancing-chemical-equations' ].titleStringProperty, [
     new IntroductionScreen( Tandem.ROOT.createTandem( 'introductionScreen' ) ),
     new GameScreen( Tandem.ROOT.createTandem( 'gameScreen' ) )
-  ];
-
-  const sim = new Sim( BalancingChemicalEquationsStrings[ 'balancing-chemical-equations' ].titleStringProperty, screens, {
+  ], {
     credits: {
       leadDesign: 'Kelly Lancaster (Java), Yuen-ying Carpenter (HTML5)',
       softwareDevelopment: 'Chris Malley (PixelZoom, Inc.)',
Index: main/joist/js/HomeScreenButton.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/main/joist/js/HomeScreenButton.ts b/main/joist/js/HomeScreenButton.ts
--- a/main/joist/js/HomeScreenButton.ts	(revision a88f873fd63c66c0e1300f2be0b96fbb614a9397)
+++ b/main/joist/js/HomeScreenButton.ts	(date 1682945078142)
@@ -15,6 +15,7 @@
 import { Shape } from '../../kite/js/imports.js';
 import merge from '../../phet-core/js/merge.js';
 import optionize from '../../phet-core/js/optionize.js';
+import IntentionalAny from '../../phet-core/js/types/IntentionalAny.js';
 import PhetColorScheme from '../../scenery-phet/js/PhetColorScheme.js';
 import PhetFont from '../../scenery-phet/js/PhetFont.js';
 import { FireListener, Node, PDOMPeer, Rectangle, Text, VBox, VBoxOptions, Voicing, VoicingOptions } from '../../scenery/js/imports.js';
@@ -36,9 +37,9 @@
 export type HomeScreenButtonOptions = SelfOptions & ParentOptions & PickRequired<ParentOptions, 'tandem'>;
 
 class HomeScreenButton extends Voicing( VBox ) {
-  public readonly screen: Screen;
+  public readonly screen: Screen<IntentionalAny, IntentionalAny>;
 
-  public constructor( screen: Screen, homeScreenModel: HomeScreenModel, providedOptions?: HomeScreenButtonOptions ) {
+  public constructor( screen: Screen<IntentionalAny, IntentionalAny>, homeScreenModel: HomeScreenModel, providedOptions?: HomeScreenButtonOptions ) {
 
     const options = optionize<HomeScreenButtonOptions, SelfOptions, ParentOptions>()( {
       cursor: 'pointer',
Index: main/joist/js/selectScreensTests.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/main/joist/js/selectScreensTests.ts b/main/joist/js/selectScreensTests.ts
--- a/main/joist/js/selectScreensTests.ts	(revision a88f873fd63c66c0e1300f2be0b96fbb614a9397)
+++ b/main/joist/js/selectScreensTests.ts	(date 1682946535275)
@@ -9,13 +9,13 @@
  */
 
 import selectScreens, { ScreenReturnType } from './selectScreens.js';
-import Screen from './Screen.js';
+import Screen, { AnyScreen } from './Screen.js';
 import HomeScreen from './HomeScreen.js';
 
 // test screen constants. Since these are tests, it is actually more valuable to typecast instead of making these actual screens.
-const a = 'a' as unknown as Screen;
-const b = 'b' as unknown as Screen;
-const c = 'c' as unknown as Screen;
+const a = 'a' as unknown as AnyScreen;
+const b = 'b' as unknown as AnyScreen;
+const c = 'c' as unknown as AnyScreen;
 const hs = 'hs' as unknown as HomeScreen;
 
 const getQueryParameterValues = ( queryString: string ) => {
@@ -56,7 +56,7 @@
 /**
  * Format the query string + all sim screens to uniquely identify the test.
  */
-const getDescription = ( queryString: string, allSimScreens: Screen[] ): string => `${queryString} ${JSON.stringify( allSimScreens )}`;
+const getDescription = ( queryString: string, allSimScreens: AnyScreen[] ): string => `${queryString} ${JSON.stringify( allSimScreens )}`;
 
 QUnit.test( 'valid selectScreens', async assert => {
 
@@ -64,7 +64,7 @@
    * Tests a valid combination of allSimScreens and screens-related query parameters, where the expectedResult should
    * equal the result returned from ScreenSelector.select
    */
-  const testValidScreenSelector = ( queryString: string, allSimScreens: Screen[], expectedResult: ScreenReturnType ) => {
+  const testValidScreenSelector = ( queryString: string, allSimScreens: AnyScreen[], expectedResult: ScreenReturnType ) => {
     const queryParameterValues = getQueryParameterValues( queryString );
 
     const result = selectScreens(
@@ -228,7 +228,7 @@
    * Tests an invalid combination of allSimScreens and screens-related query parameters, where selectScreens should
    * throw an error
    */
-  const testInvalidScreenSelector = ( queryString: string, allSimScreens: Screen[] ) => {
+  const testInvalidScreenSelector = ( queryString: string, allSimScreens: AnyScreen[] ) => {
     const queryParameterValues = getQueryParameterValues( queryString );
     const description = getDescription( queryString, allSimScreens );
 
Index: main/joist/js/Screen.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/main/joist/js/Screen.ts b/main/joist/js/Screen.ts
--- a/main/joist/js/Screen.ts	(revision a88f873fd63c66c0e1300f2be0b96fbb614a9397)
+++ b/main/joist/js/Screen.ts	(date 1682946754400)
@@ -72,9 +72,11 @@
 // Accept any subtype of TModel (defaults to supertype), and any subtype of ScreenView (defaults to subtype).
 type CreateView<M extends TModel, V> = ( model: M ) => V;
 
+export type AnyScreen = Screen<IntentionalAny, ScreenView>;
+
 // Parameterized on M=Model and V=View
 // The IntentionalAny in the model type is due to https://github.com/phetsims/joist/issues/783#issuecomment-1231017213
-class Screen<M extends TModel = IntentionalAny, V extends ScreenView = ScreenView> extends PhetioObject {
+class Screen<M extends TModel, V extends ScreenView> extends PhetioObject {
 
   public backgroundColorProperty: Property<Color> | Property<string> | Property<Color | string>;
 

@samreid
Copy link
Member

samreid commented May 1, 2023

I improved and committed the patch above. It appears to address the concerns raised by @pixelzoom in the topmost comment. @zepumph and I will meet next week to discuss.

@samreid samreid removed their assignment May 5, 2023
zepumph added a commit to phetsims/number-compare that referenced this issue May 9, 2023
zepumph added a commit to phetsims/beers-law-lab that referenced this issue May 9, 2023
zepumph added a commit to phetsims/number-suite-common that referenced this issue May 9, 2023
@zepumph
Copy link
Member

zepumph commented May 9, 2023

@samreid and I dove into this again. The contravariance problem (where createView gets a parameter of Model for it) is inherent to how we have written Screen. This is not something that we can just TypeScript to get around. Instead, we punted, and @samreid's commits last week put the burden on joist instead of on all main files. Nice work! The worst line of code is

joist/js/Sim.ts

Lines 427 to 429 in 0e249f9

if ( screen.model.step && dt ) {
screen.model.step( dt );
}

because it thinks screen.model is any, but that is only inside Joist. Usages outside of joist, for example using the selectedScreenProperty in Number Play get around this with an instanceof check so that we can use specific features of that screen after the automatic type narrowing.

This is potentially a good-enough solution, but we will need to continue to be vigilant in Joist that we don't make a type error if we ever call functions on the model of an AnyScreen.

We will continue with the "nuclear solution" over in #922

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants