Restrict emits from EventEmitter3 - typescript-generics

Related to the accepted answer: https://stackoverflow.com/a/63639280/17928771
EventEmitter3 is a generic class that takes an (as one example) Interface of Events/Handlers. I'm trying to restrict IRaceManager emits to IRaceEvents. I have tried:
Attempt 1.
class POSRaceManager implements IRaceManager extends EventEmitter<IRaceEvents> {}
let raceManager: IRaceManager = new POSRaceManager();
raceManager.emit('moo'); // error, no `emit` on IRaceManager
Attempt 2.
interface IRaceManager extends EventEmitter<IRaceEvents> {} // TS2749: 'EventEmitter' refers to a value, but is being used as a type here. Did you mean 'typeof EventEmitter'?
The following attempt works, but doesn't limit the emit or on to the IRaceEvents (or an extension of IRaceEvents)
Attempt 3.
This fails:
type RaceEventEmitterType<T extends IRaceEvents> = InstanceType<typeof EventEmitter>;
type IRaceManager<T extends IRaceEvents> = RaceEventEmitterType<T>;
let raceManager: IRaceManager = new POSRaceManager<IRaceEvents>;
raceManager.emit("moo"); // no error because of `InstanceType<typeof EventEmitter>`
Final attempt.
type RaceEventEmitterType<T extends IRaceEvents> = InstanceType<typeof EventEmitter<IRaceEvents>>; // Need to investigate what this does, actually. I overlooked a syntax error before.
Any ideas to restrict emissions from raceManager<?> to T extends IRaceEvents only?
Edit:
I am currently settled on the following (which works, I am just wondering if there is a way to resolve as above):
type RaceEventEmitter<T extends IRaceEvents> = InstanceType<typeof EventEmitter>;
export type IRaceManager<T extends IRaceEvents> = RaceEventEmitter<T>;
class POSRaceManager extends EventEmitter<IRaceEvents> implements IRaceManager<IRaceEvents>;

Related

What does <T = unknown> mean in a generic class in TypeScript?

In some code I am reading, I see a class declared thus:
export abstract class ClassName<T = unknown> implements InterfaceName { … }
I am familiar with unconstrained generics (class C<T> {…) and constrained generics (class C<T extends S> {…), but what does = unknown mean, and what effect does it have compared to no constraint at all?
Surely, absent an extends, code within the generic class must treat T as if it were unknown already? And if <T = S> means to pin type T to exactly type S then why make it a generic at all?
This is default parameter type. It is type, that is resolved, when the type constructor is given without the type parameters.
Consider this class definition:
export class Class<T = unknown> { }
Then you can create instances either with explicit type for T or without.
const x = new Class()
const y = new Class<unknown>()
const z = new Class<number>()
Here, type of x and y will both be Class<unknown>, whereas z would be Class<number>. So it means, that declaring class with <T = unknown> is the same as <T>.
So for this particular case, it doesn't make much sense, but if you choose anything else than unknown, then it will serve as default type parameter.
Note, that it doesn't serve as constraint, that means that if you declare
export class ClassB<T = string> { }
you can still declare:
const z = new ClassB<number>()

flowtype: $Subtype and typeof fail when used in generic types

It appears that class types in flow always refer to instances of that class and one uses typeof to refer to the actual class itself. So, if I want a variable to refer to a subclass (not an instance) of a base class, I can do:
class MyBaseClass {}
class MySubClass extends MyBaseClass {}
let a: $Subtype<MyBaseClass> = MySubClass; // fails
let b: $Subtype<MyBaseClass> = new MySubClass(); // works, but I don't want this.
let c: $Subtype<typeof MyBaseClass> = MySubClass; // works! Ok, we're good
However, I can't seem to do this with type parameters! For example, the following:
type GenericSubclass<T> = $Subtype<typeof T>;
// fails with `^ identifier `T`. Could not resolve name`
If I try the following Typescript trick (see Generic and typeof T in the parameters), it also fails:
type ValidSubclass<T> = { new(): T };
const c: ValidSubclass<BaseClass> = MySubClass;
// fails with: property `new`. Property not found in statics of MySubClass
Note that I tried new, __proto__ and constructor.
What gives? Is there a workaround?
typeof MyBaseClass
is
Class<MyBaseClass>
so you can do
type GenericSubclass<T> = $Subtype<Class<T>>;

Making a minecraft mod in java. Creating and registering an instance

I'm trying to make an uranium ingot that gives players that hold it in their inventory a wither effect. I got some tips from the minecraft forums, they told me to do to make my item give me the wither effect.
Re: 1.10.2 Item has wither « Reply #2 on: Today at 02:29:58 am » QuoteThank You Create a class that extends Item and overrides
Item#onUpdate.
In your override, check if the entityIn argument is an instance of EntityLivingBase. If it is, cast it to EntityLivingBase and call EntityLivingBase#isPotionActive to check if it has the MobEffects.WITHER effect active. If it doesn't, create a PotionEffect and call EntityLivingBase#addPotionEffect to add it.
My Question
Create and register an instance of this class instead of Item.
The last line is what im confused on.
Here is the class i made that he told me to do. Also please inform me if i didnt do something else right in this class
package item;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.init.MobEffects;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.potion.PotionEffect;
import net.minecraft.world.World;
public class UraniumIngotEffect extends Item{
#Override
public void onUpdate(ItemStack stack, World worldIn, Entity entityIn, int itemSlot, boolean isSelected) {
if(entityIn instanceof EntityLivingBase){
Object EntityLivingBase = ((EntityLivingBase) entityIn).isPotionActive(MobEffects.WITHER);
}else{
Object PotionEffect = new PotionEffect(MobEffects.WITHER);
}
super.onUpdate(stack, worldIn, entityIn, itemSlot, isSelected);
}
}
You need to make the item object in your mod hold the onUpdate method.
This means:
have a class that extends Item(your uranium ingot)
Register the item in the item loader
Item myurnanium = new UraniumIngot();
GameRegistry.register(myuranium);
and of course make the proper json files so the item will render properly.
I suggest you read:
http://bedrockminer.jimdo.com/modding-tutorials/basic-modding-1-8/first-item/

Variable is not of the type class

I have a custom class for holding a collection of data.
I use this class throughout my code, and it works without a hitch, except for in one place, when I need to pass the class object to a method. Here is some very basic code to demonstrate what I am seeing.
public class doSomething
static void myMethod(customClass_myItem) {}
public class customClass
public str classMethod() {}
form method
customClass myItem = new customClass();
myItem.classMethod(); //this works, so I know the class is good
doSomething::myMethod(myItem); //Gives error: variable is not of the type CLASS.
I am completely lost here. If I couldn't use the class at all, I would understand, but with it not working when passed to another method.. doesn't make any sense. If I put in a breakpoint, the debugger indicates myItem is a class of the correct type.
Any suggestions?
Thanks
Your myMethod expects an object of class customClass_myItem (or a descendant) not customClass.
If you change your parameter type to object it should work.
static void myMethod(Object o) {}

asmock Previous method requires a return value or an exception to throw

Trying to get my head around asmock to implement some unit testing in my project. I want to test my MainMediator and since there are objects that get created in my MainMediator onRegister call, I'm thinking that I should mock those objects.
Hopefully that's correct to begin with!
I have something like this
[Rule] public var includeMocks : IncludeMocksRule = new IncludeMocksRule([
IEventDispatcher, IMyService
]);
[Before]
public function setUp():void {
mockRepository = new MockRepository();
mainView = new MainView();
mainMediator = new MainMediator();
dispatcher = IEventDispatcher(mockRepository.createStub(IEventDispatcher, StubOptions.NONE));
myService = IMyService(mockRepository.createStub(IMyService, StubOptions.NONE));
mockRepository.stubEvents(dispatcher);
SetupResult.forCall(chatService.clientID)
.returnValue("");
mockRepository.replayAll();
mainMediator.eventDispatcher = dispatcher;
myService.eventDispatcher = dispatcher;
mainMediator.service = myService;
....
mainMediator.onRegister();
}
When I step through the test and stop at mockRepository.stubEvents(dispatcher). I can see errors in the myService class
Error: Previous method IMyService/clientID/get(); requires a return value or an exception to throw. clientID just happens to be my first property hence why it's being picked on.
I thought either that StubOptions.NONE would mean that no properties get stubbed or that my SetupResult.forCall(myService.clientID) would fix it but none did.
Answering to the question in the comment re: the eventDispatcher, I have:
MyService extends ServiceBase implements IMyService
where ServiceBase extends Actor
I found that I need the following in IMyService to get access to the eventDispatcher.
function get eventDispatcher():IEventDispatcher;
function set eventDispatcher(dispatcher:IEventDispatcher):void;
Not too sure if that is correct. Bit confused now.
Can someone please tell me where I'm going wrong?
Thanks!
This is a common problem when mocking concrete classes, rather than interfaces: if the constructor calls another method (or property getter), it will return null because it hasn't been mocked yet.
There's not really anyway to workaround it, except to abstract your class through an interface and mock that.

Resources