// Generic METHODS (own type parameters) monomorphize per call site with // STATIC dispatch — the forms that would need dynamic machinery keep // specific fences. // A receiver whose runtime class may hold an override: generic methods // have no per-instantiation vtable slot, so only statically-exact // receivers resolve the override set. class VBase { m(x: T): string { return `b:${String(x)}`; } } class VLeaf extends VBase { m(x: T): string { return `l:${String(x)}`; } } function throughBase(r: VBase): string { return r.m(1); } console.log(throughBase(new VLeaf())); // Mixing generic and non-generic declarations of one name across the // hierarchy: the two dispatch worlds cannot see each other's overrides. class PlainBase { f(x: number): number { return x; } } class GenericOver extends PlainBase { f(x: T): T { return x; } } new GenericOver(); // `this` in an object-literal generic method is the receiver object — // records don't model it. const withThis = { n: 1, m(x: T): T { const self = this; return x; }, }; console.log(withThis.m(2)); // The defining literal must sit at module scope: compiled instances are // plain module functions and cannot capture the enclosing frame. function makeObj(): number { const local = { m(x: T): T { return x; } }; return local.m(3); } console.log(makeObj()); // Static resolution needs a never-reassigned binding: this let is written // again with a same-typed literal whose body differs — resolving against // the first would silently call the wrong body. let rebindable = { m(x: T): T { return x; } }; console.log(rebindable.m(4)); rebindable = { m(x: T): T { return x; } }; // An interface-typed receiver has no defining object literal to resolve. interface HasGeneric { m(x: T): T; } const viaInterface: HasGeneric = { m(x: T): T { return x; } }; console.log(viaInterface.m(5)); // Generic methods as VALUES: bound-method references stay fenced (class // receivers), and an unpinned object-literal reference keeps the // generic-value fence. class Inst { g(x: T): T { return x; } } const bound = new Inst().g; const util = { id(x: T): T { return x; } }; const unpinned = util.id;