Использование такой структуры очень популярно:
function foo() {
let someProperty;
// инициализация каких-нибудь свойств
function someMethod() {
// выполнение операций над `someProperty`
// и другими свойствами
}
// Несколько дополнительных методов
return {
someMethod,
// и остальные методы
};
}
Этот паттерн называют паттерном раскрывающегося модуля и он очень популярен в JavaScript (использует преимущества замыканий в JavaScript).
Если вы используете файловые модули (которые следует использовать, поскольку глобальный контекст - это плохо), тогда ваш файл фактически такой же. Однако, существует множество случаев, в которых люди пишут код таким образом:
let someProperty;
function foo() {
// какие-то операции
}
foo(); // вызов
someProperty = 123; // инициализация
// еще инициализации
// и в конце
export function someMethod() {
}
Несмотря на то, что я не большой фанат наследования, я считаю, что использование классов помогает людям лучше организовать свой код. Тот же разработчик интуитивно написал бы следующее:
class Foo {
public someProperty;
constructor() {
// какая-то инициализация
}
public someMethod() {
// код метода
}
private someUtility() {
// код метода
}
}
export = new Foo();
И это не только для разработчиков, создание инструментов разработки, которые обеспечивают отличную визуализацию классов, встречается гораздо чаще. И есть еще один паттерн, который ваша команда должна понимать и поддерживать
PS: На мой взгляд, нет ничего плохого в неглубокой иерархии классов, если они обеспечивают повторное использование и сокращение кодовой базы.