You will get the properly typed pointer to object from new, so if you want to play it completely safe wrt UB, it can be stashed away alongside the array in the public class; this adds sizeof(T*) to the latter, but avoids casts entirely.
But, yes, you do technically need std::launder to get it directly via the array.
But, yes, you do technically need std::launder to get it directly via the array.