An init method seems fine. The “problem” here is that UE C++ practices deviate quite a bit from standard raw C++. As mentioned before, you never call the constructor directly, but that is not the only reason why you should keep the constructor as static as possible. UE creates default objects for each class, which run the constructor and basic initialization and you can access them at any point in the engine to read default values of a class.
DamageTypes are a good example: Say you create a derived blueprint class of a custom C++ DamageType class. In that blueprint asset you can now override default values, i.e. a flag for a poison debuff. Now when UE creates this class’ default object at runtime it will call the constructor and afterwards initialize the overriden properties. This is also why UE will complain if you change the name of UProperties, it can no longer assign values correctly. (The same system is used if you place actors in a level and change their values)
As far as I know the default object is also used for faster runtime construction of new objects by using them as a template.
When you spawn an actor, then UE will run a bunch of other methods on it before spawn returns (i.e. PostInitalizeComponents / BeginPlay). If you really need to set data before that you can use SpawnActorDeferred which will only do the most rudimentary initialization. You can then configure the object and use FinishSpawningActor to run the rest of the cycle.
greetings,
FTC