The code example below shows how to construct a Proxy hierarchy that mimics class and subclass. It accomplishes this by wrapping a standard object with multiple Proxy objects and judicious use of the handler get option.
Proxy's handler is a form of the Mix-in Pattern. We can simulate subclassing using the mix-in pattern.
The code contains two types of Proxy "classes": EmitterBase and EmitterNet. It uses those to collect statistics specific to a vanilla EventEmitter or to one of its subclasses Net. EmitterNet does not duplicate features of EmitterBase, but instead reuses Base by wrapping around it. Note, in the example, we wrap http.Server: a subclass Net and a subsubclass of EventEmitter.
The handler passed to Proxy implements all of the behavior for a subclassed Proxy. Multiple handler versions implement subclasses. For example, in EmitterBase we collect statistics on calls to on and emit (count the number of calls). EmitterBase also implements phantom members and methods to track and report on those counts. This is the equivalent of a base class with those methods and members. See the handler in wrapEmitterBase.
Next, we create a Proxy "subclass" using another handler (see wrapEmitterNet) which implements two new phantom members for counting Net specific calls (listen and close). It also implements a method stats() that overrides a method from the base class as well as calling the overridden method.
The Proxy standard gives us enough features to implement Proxy subclassing without resorting to class wrappers and messing with this.
import * as util from 'node:util';
import http from 'node:http';
import { EventEmitter } from 'node:events';
async function DemoProxyHierarchy()
{
  const greeter = wrapEmitterBase(new EventEmitter());
  greeter.on("hello", (person) => console.log((`Hello, ${person}!`)));
  greeter.emit("hello", "World");
  greeter.emit("hello", "Benjamin");
  console.log(`on   calls: ${greeter.countOn}`);
  console.log(`emit calls: ${greeter.countEmit}`);
  console.log(`statistics: ${JSON.stringify(greeter.stats())}`);
  const stats = new Promise((Resolve, reject) => {
    let steps = 0;
    const server = http.createServer((req, res) => { res.end() });
    const netWrapper = wrapEmitterNet(server) as any;
    const done = () => {
      if (++steps > 2) {
        console.log(`\non   calls: ${netWrapper.countOn}`);
        console.log(`emit calls: ${netWrapper.countEmit}`);
        netWrapper.close(() => Resolve(netWrapper.stats()));
      }
    };
    netWrapper.listen(8080, done);
    http.get('http://localhost:8080', done);
    http.get('http://localhost:8080', done);
  });
  return stats.then(s => console.log(`net  stats: ${JSON.stringify(s)}`));
}
function wrapEmitterBase(ee: EventEmitter)
{
  const stats = { on: 0, emit: 0 };
  const handler = {
    get: (target, key) => {
      switch (key) {
        case "countOn":   return stats.on;
        case "countEmit": return stats.emit;
        case "stats":     return () => ({ ...stats });
        case "on":        { stats.on++;   break; }
        case "emit":      { stats.emit++; break; }
      }
      return target[key];
    },
  }
  return new Proxy(ee, handler);
}
function wrapEmitterNet(ee: EventEmitter)
{
  const stats = { listen: 0, close: 0 };
  const handler = {
    get: (target, key) => {
      switch (key) {
        case "stats":  {
          return () => ({ ...target[key](), ...stats });
        }
        case "listen": { stats.listen++; break; }
        case "close":  { stats.close++;  break; }
      }
      return target[key];
    },
  };
  return new Proxy(wrapEmitterBase(ee), handler);
}
// IIFE
(()=> { await DemoProxyHierarchy() })();
/* Output:
Hello, World!
Hello, Benjamin!
on   calls: 1
emit calls: 2
statistics: {"on":1,"emit":2}
on   calls: 1
emit calls: 5
net  stats: {"on":2,"emit":6,"listen":1,"close":1}
*/