TS isn't OO or non-OO. You can use it within Domain model methods, service methods, or high-level app methods. It just means you can read the business intent of the program without winding thru a million callbacks and 'black magic'.
That's why microsoft introduced async/await. It turns obscure looking send-a-callback (delegate) and exit, process-the-callback-in-separate-method (required) style - into a readable transaction script.
GOTOs are bad because they break the readable flow of a transaction script, making it a bad one.
a) Transaction script gone wrong is an antipattern. For example, one huge method, no or few method calls, etc. different levels of operations in the same method (refactor them to methods). Discrete steps of the business process together in one method (break them into methods or separate classes. Lots of business objects? Use DDD service pattern).
b) NOT using TS correctly is an antipattern. For example tons of inter-app messaging, event firing, etc so you can't read thru and see the business process (functional requirement for tech apps). Low level details (tech) mixed with functional work. Over separation of a business activity that should be visible on one page.
TS usage should be fractal, with each zoom in drilling down to more details TS style logic. High level: you see method calls and DDD service use. mid level can be a bit of a mix. Lower down is mostly domain object method / property calls and in there the finest logic details.
Throwing TS under the bus because it can be abused, or preventing its use, just kicks the can down the road - the dev that can't group and separate and doesn't know SRP (single responsibility) / Cohesion will screw up other styles, too. The answer is to train them on the business process and give examples of grouping and separating - which should be done by business/functional requirement (vertical slice) not technology (horizontal slice).
- put logic that just deals with one domain object or other instances of its type in the DO. Don't reference other object types from domain objects (person.orders) or inject anything into a domain object.(other DO or repository, etc). It violates SRP simple as that. [low level transaction scripts in the methods]
- When you need something like person.orders, or feel like you need to inject something, make a DDD service (not serialized, no persistent properties after each use). Inject e.g., a person, and the others collection (repository or IQueryable etc). Do the work there. [mid level transaction scripts here]
- combine operations on domain objects and DDD svcs in an 'app methods' category of DDD services.
- construct and call those from the highest level of the program
at each level, it looks like a TX script, follow the rules, though. Keep methods small. You will be able to read it then!
Note: In the link provided in the other answer, Fowler tells you how to make a transaction script right vs. wrong:
https://www.informit.com/articles/article.aspx?p=1398617
He also does suggest that it isn't OO. I think you can hybrid it to OO and use TS pros (readability and a hundred pros of that), and the hundreds of OO pros too. That is to say, you can put TS elements in a domain model, and compose domain model use in a higher level TS.
Also consider the definition of a transaction script as a single database transaction. Since your domain model should NOT have the repositories injected (inject domain objects into the repositories), you can actually organize it like that, calling the relevant repositories to (de)persist at the highest level. But if that's not the case, the point is to have a stream of readable code that is not over-separated.
The problem with lambasting TS is it makes people think SRP is all about SoC (separation of concerns) and they never have to worry about Cohesion (keep same things together, which implies SoC too but demands organization). Thus well intentioned engineers just separate things into a million pieces (because more is better) and it's tougher to discern the logic.