Button callback based on the objects particle system?
An Object property?

Make it an object property then it is set on a per object basis. 

Since the property is defined on an Object class, then self in an update method is an object of type bpy.types.Object of which context.object is an instance .  If it was registered as a scene property, self would be a scene.

If it were a scene property, I would set the PS type for all objects with it. 

def emitter_update(self, context):
    toogle = self.my_prop_grp.emitter_hair
    pobs = [o for o in self.objects if len(o.particle_systems)]
    for ob in pobs:
        part = ob.particle_systems[0]  
        settings = part.settings
        settings.type = 'EMITTER' if toogle else 'HAIR'


Consult blender docs re naming conventions for classes, methods.

One of my pet hates: when context is passed as a function argument .. use it. Get out of the habit of bpy.context.foo.blah.bar...  

Added a poll method in panel so it doesn't show when context object has no particle system.

import bpy
from bpy.props import  BoolProperty, PointerProperty
from bpy.types import PropertyGroup, Panel, Object

def emitter_update(self, context):
    toogle = self.my_prop_grp.emitter_hair
    part = self.particle_systems[0]  
    settings = part.settings
    settings.type = 'EMITTER' if toogle else 'HAIR'

class MyParticleSettings(bpy.types.PropertyGroup):       
    emitter_hair: BoolProperty(update = emitter_update)

class VIEW3D_PT_toggle_ps(Panel):
    """Test"""

    bl_label = "My Panel"
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"
    bl_category = "View"

    @classmethod
    def poll(self, context):
        ob = context.object
        return ob and len(ob.particle_systems)

    def draw(self, context):
        ob = context.object
        layout = self.layout
        layout.label(text="My problem:")
        layout.prop(ob.my_particle_settings, 'emitter_hair',  text="Toggle")


classes = (MyParticleSettings,
        VIEW3D_PT_toggle_ps)  


def register():
    for cls in classes:       
        bpy.utils.register_class(cls)

    Object.my_particle_settings = PointerProperty(type=MyParticleSettings)


def unregister():
    for cls in reversed(classes):       
        bpy.utils.unregister_class(cls)

if __name__ == "__main__":
    register()


I imagine this will be extended, otherwise could simply put the enum in layout

row.prop(part, "type", expand=True)


or a window manager context toggle operator.

TIP.

In version 2.7x could reload scripts using the F8 key. It is  AFAIK not mapped to a key in default 2.8.  

Either map it to a key, run in python console.

bpy.ops.script.reload()


Pre(ap)ending a simple operator button draw method to headers of both text editor and python console provides a couple of handy and often used buttons

For example when testing above, posted with ob.my_prop_group in the draw method after it had been renamed to ob.my_particle_settings.  As I hadn't reloaded scripts it was still registered from a previous test run, and worked as expected.  

Running after reloading scripts will throw errors for such unregistered props.