Question: Extracting a nested type from the generic parameter of a generic class in TypeScript

I'm working on a TypeScript project and I have a generic class AbstractDAL with a generic type parameter T_DEFAULT_RETURN. Inside the AbstractDAL class, I'm trying to extract a nested type that is specified within the T_DEFAULT_RETURN generic type parameter, but I'm facing some challenges.
Here's the simplified code structure I have:
class A {
    alpha() { }
};

class B extends A {
    beta() { }
};

abstract class AbstractDAL<
    T_DEFAULT_RETURN extends BaseEntity = BaseEntity,       
    T_DATA = T_DEFAULT_RETURN extends BaseEntity<infer D> ? D : never
> {
    get result() {
        return {} as T_DATA
    }
}

class BaseEntity<       
    T_DATA extends A = A
> { }



class TestDAL extends AbstractDAL<TestEntity> {
    delta() {
        this.result.alpha // should also be beta, not just alpha
    }
}

class TestEntity extends BaseEntity<B> { }

In the above code, the AbstractDAL class is defined with a generic type parameter T_DEFAULT_RETURN, and I'm trying to extract a nested type from this parameter. I have used a conditional type with infer and a helper type T_DATA to accomplish this. However, the inferred type for T_DATA is A instead of the expected type B.
Is there a way to correctly extract the nested type B from the T_DEFAULT_RETURN generic type parameter within the AbstractDAL class? If so, what modifications are needed in the code to achieve this?


Answer:
The problem is that BaseEntity<T> does not depend on T structurally, and thus inference from BaseEntity<T> to T is, at best, unreliable.

TypeScript's type system is largely structural and not nominal.  That means types are compared by their structure or shape, and not by what they are named or where they are declared.  If type X and type Y are both object types with the same members, then they are the same type:
interface X { w: string; z: number; }
let x: X = { w: "abc", z: 123 };

interface Y { w: string; z: number; }
let y: Y = { w: "def", z: 456 };

x = y; // okay
y = x; // okay

In the above it doesn't matter whether you use the name X or the name Y to refer to the type.  They are interchangeable.
This extends to generics as well.  If you have a generic type that doesn't use its type parameter inside the type definition, like
interface F<T> { w: string; z: number }

then all types you create by specifying T with a type argument will be identical to each other, and thus interchangeable:
let fs: F<string> = x; // okay
let fn: F<number> = y; // okay
fs = fn; // okay
fn = fs; // okay

There is no difference between F<string> and F<number>, or between either of them and X or Y.  We don't care about the name F<string>, just the shape { w: string; z: number }.
And that's indicative of a problem in the code.  Type inference, such as what you get when you use infer in a conditional type, can only work consistently if it is inferring from structure.
Asking TypeScript "given G<T>, what type is T", the compiler cannot necessarily answer correctly.  It depends strongly on the definition of G.  For example, given our F<T> definition above, where F<T> is identical to X for all T, then the information you want is essentially gone.  If I asked you to tell me which T makes F<T> equal to { w: string; z: number }, there's no principled away to answer.  Indeed any answer is equally correct.  There's no principled way to say that a particular { w: string; z: number } came from F<string> vs F<number>.  Sometimes you'll find that the compiler does infer from names, but you can't rely on it.
So, in general, you should never have unused type parameters.  See the TypeScript FAQ entry Why doesn't type inference work on this interface: interface Foo<T> { }?.

The solution is therefore to add some structure to your type that depends on the generic type parameter.  A BaseEntity<T> should have something to do with T!  For example, if you add a property of type T, everything starts working:
class BaseEntity<D extends A = A> {
    declare d: D // <-- make it structurally dependent
}

class TestDAL extends AbstractDAL<TestEntity> {
    delta() {
        this.result.alpha
        //^? (property) AbstractDAL<TestEntity, B>.result: B            
    }
}
class TestEntity extends BaseEntity<B> { }

That declare field is just me telling the compiler that a BaseEntity<D> has a field of type D at key d without having to actually initialize it.  In practice you should always initialize your class fields. The compiler will allow you to write new BaseEntity<string>().d.toUpperCase() but it will explode at runtime if d wasn't initialized.  I'm more worried about typings than initialization.
That's just an example.  You should try to give BaseEntity<T> some structural dependence on T that makes sense for the actual use case, and only resort to a "phantom" property like declare d if you really don't have anything better.
Playground link to code