Pas au niveau du typage non, plutôt au niveau du changement de contenu de la donnée. Les objets immutables peuvent être partagés tranquillement entre des threads, être utilisés par des fonctions de hash, être triés ou classés avec l'assurance qu'il va pas soudain il y avoir une modification de leur état qui va rendre les choses incohérentes.
Autre exemple simple, imagine une classe Triangle composée de 3 Points (p1, p2, p3).
Si les points sont immuables, tu es sûr que ton triangle, une fois construit, reste un triangle.
En revanche que peux-tu faire si soudain les points sont modifiés de l'extérieur?
p1 = new Point(10, 30);
p2 = new Point(10, 40);
p3 = new Point(20, 40);
triangle = new Triangle(p1, p2, p3);
p3.setX(10);
p3.setY(30);
p2.setX(10);
p2.setY(30);
Ben "triangle" c'est plus un triangle, et il ne sait pas du tout qu'il a été modifié de l'extérieur.
En revanche avec des points immuables, tu peux obliger l'utilisateur à passer par des méthodes de la classe Triangle s'il veut changer quelque chose. Ou encore mieux, on peut décider qu'il n'a qu'à créer un nouveau triangle et effacer l'ancien.
Des petits malins viendront dire qu'il suffit d'avoir un système d'évènement (Signaux, Observer/Obervable) qui permettrait au triangle de s'abonner à un système de notification et réagir quand un de ses points est modifié, et bien non. Cette façon de programmer qui a été popularisée par les frameworks de binding UI > données est 9 fois sur 10 une mauvaise idée. Elle demande beaucoup plus de tests, crée des références croisées et du code spaghetti difficile à suivre tout en étant au final 1000 fois moins élégante qu'une relation parent-enfant dans laquelle l'enfant est immuable.
L'utilisation judicieuse de l'immuabilité est selon moi l'un des critères qui peut faire sortir du lot un développeur par rapport à un autre, sans exagération.