It doesn't defeat the purpose. It only mutates if there is actually a change to the data structure. When used properly, timm works great.
The (potential) problem is that it is still possible to mutate objects without the use of timm's utility functions.
If you value the performance benefits (no penalty for freezing objects since timm doesn't do that), and understand that to get the benefits, you must only mutate objects using timm, choose timm.
If you value the additional safety other libraries provide, then absolutely use one of those. It all depends on the use case.
You don't need to freeze objects if you are doing it properly. You could even do static analysis to know (by checking to see if you're reassigning object properties, etc).
The (potential) problem is that it is still possible to mutate objects without the use of timm's utility functions.
If you value the performance benefits (no penalty for freezing objects since timm doesn't do that), and understand that to get the benefits, you must only mutate objects using timm, choose timm.
If you value the additional safety other libraries provide, then absolutely use one of those. It all depends on the use case.
You don't need to freeze objects if you are doing it properly. You could even do static analysis to know (by checking to see if you're reassigning object properties, etc).