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

Typescript: How can Voicing mix into a parametric class? #1349

Closed
zepumph opened this issue Feb 7, 2022 · 8 comments
Closed

Typescript: How can Voicing mix into a parametric class? #1349

zepumph opened this issue Feb 7, 2022 · 8 comments

Comments

@zepumph
Copy link
Member

zepumph commented Feb 7, 2022

Over in phetsims/ratio-and-proportion#384, I wanted to add voicing to a RectangularRadioButtonGroup, but we don't seem to support this:

class TickMarkViewRadioButtonGroup extends Voicing( RectangularRadioButtonGroup < TickMarkView >, 2 ) {
  ...
}

Notice how Webstorm autoformatted it? The error we get by typescript is:

TS2365: Operator '' cannot be applied to types 'typeof RectangularRadioButtonGroup' and 'typeof TickMarkView'.

If I remove the parametric type:
TS2508: No base constructor has the specified number of type arguments.

@jonathanolson, perhaps we can talk about this as part of our review in #1340.

This is only blocking publication of Ratio and Proportion as far as I know.

@jonathanolson
Copy link
Contributor

Seems problematic, I'll look into it.

@zepumph
Copy link
Member Author

zepumph commented Feb 7, 2022

@jonathanolson and I talked about it, and were able to get things working with:

type ConstructorOf<C> = { new( ...args: any[] ): C; };

class TickMarkViewRadioButtonGroup extends Voicing<ConstructorOf<RectangularRadioButtonGroup<TickMarkView>>>( RectangularRadioButtonGroup, 2 ) {

We are still working on a way to move that to the mixin files, instead of every usage, but at least this can be non blocking at this point. I'll try it out over in phetsims/sun#699 and phetsims/ratio-and-proportion#384

@jonathanolson
Copy link
Contributor

I'll look into this also, I'm looking at a few mixin typescript things.

@zepumph zepumph removed their assignment Feb 8, 2022
@jonathanolson
Copy link
Contributor

image

This looks like it will be an issue...

@jonathanolson
Copy link
Contributor

Actually this is type-checking

const GenericMix = memoize( <SuperType extends Constructor>( type: SuperType ) => {
  const result = class extends type {
    _someField: string;

    constructor( ...args: any[] ) {
      super( ...args );

      this._someField = 'Testing';
    }

    get someField(): string { return this._someField; }

    set someField( value: string ) { this._someField = value; }
  };

  return result;
} );

class PropertyMixed<T> extends GenericMix( Property )<T> {
  constructor( value: T, options?: PropertyOptions<T> ) {
    super( value, options );
  }
}

const pMixed1 = new PropertyMixed<number>( 5 );
console.log( pMixed1.value, pMixed1.someField );

const pMixed2 = new PropertyMixed<string>( 'hi' );
console.log( pMixed2.value, pMixed2.someField );

Didn't realize we can just have the mix be... generic, and then specify a type parameter to the mixed type. From microsoft/TypeScript#26542 (comment)

@jonathanolson
Copy link
Contributor

The key line is:

class PropertyMixed<T> extends GenericMix( Property )<T> {

@zepumph does this seem to resolve this issue for you?

@zepumph zepumph self-assigned this Feb 8, 2022
@zepumph
Copy link
Member Author

zepumph commented Feb 8, 2022

That seems pretty nice on paper! I will want to try it out in my mixins after I get some bug fixes pushed over in #1340

@jonathanolson jonathanolson removed their assignment Feb 8, 2022
jonathanolson added a commit to phetsims/wilder that referenced this issue Feb 8, 2022
@zepumph
Copy link
Member Author

zepumph commented Feb 23, 2022

Thanks for the help! I tried this out and it worked perfectly.

Index: js/common/view/TickMarkViewRadioButtonGroup.ts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/js/common/view/TickMarkViewRadioButtonGroup.ts b/js/common/view/TickMarkViewRadioButtonGroup.ts
--- a/js/common/view/TickMarkViewRadioButtonGroup.ts	(revision b50407d9c5b80d533d65fd7f078ac39ac6f11b2d)
+++ b/js/common/view/TickMarkViewRadioButtonGroup.ts	(date 1645644173340)
@@ -7,7 +7,7 @@
  */
 
 import merge from '../../../../phet-core/js/merge.js';
-import { ParallelDOM, Path, PathOptions, voicingUtteranceQueue } from '../../../../scenery/js/imports.js';
+import { ParallelDOM, Path, PathOptions, Voicing, voicingUtteranceQueue } from '../../../../scenery/js/imports.js';
 import eyeSlashSolidShape from '../../../../sherpa/js/fontawesome-5/eyeSlashSolidShape.js';
 import RectangularRadioButtonGroup from '../../../../sun/js/buttons/RectangularRadioButtonGroup.js';
 import ActivationUtterance from '../../../../utterance-queue/js/ActivationUtterance.js';
@@ -21,7 +21,7 @@
 // constants
 const ICON_SCALE = 0.45;
 
-class TickMarkViewRadioButtonGroup extends RectangularRadioButtonGroup<TickMarkView> {
+class TickMarkViewRadioButtonGroup extends Voicing( RectangularRadioButtonGroup, 2 )<TickMarkView> {
 
   /**
    * @param tickMarkViewProperty
@@ -80,6 +80,8 @@
     } ];
     super( tickMarkViewProperty, radioButtonItemData, options );
 
+    this.voicingContextResponse = 'a contextualized test';
+    this.voicingSpeakContextResponse();
     const tickMarkContextResponseUtterance = new ActivationUtterance();
     const voicingResponsePacket = new ResponsePacket();
     const tickMarkVoicingContextResponseUtterance = new ActivationUtterance( {

@zepumph zepumph closed this as completed Feb 23, 2022
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

2 participants