Assuming the text is on a single line, you could use the TMP_Text.preferredWidth or TMP_Text.textBounds and if those even use any of the information contained in the TMP_Text.textInfo and sub structures.
In case you are not familiar with the textInfo class, once a text object has been processed (generated) this class contains information about the text object like number of characters, spaces, words, lines, links, etc. It also contains several sub structures like characterInfo[ ], wordInfo[ ], lineInfo[ ], etc. which contain information about the characters, words, lines, etc.
To help you visualize this information, there is a utility script called TMP_TextInfoDebugTool.cs which you can add to any TMP object to show the characters, words, lines, etc.
By using the extend of the text bounds, making sure you factor in the transform position, you can calculate the position of the left or right side of the text object so you can check where either of those are at any given point. Again, if you add that TMP_TextInfoDebugTool.cs script to your text object, you can show the text bounds and also look at how those are handled to draw the bounds.
Between the text bounds, mesh bounds, the textInfo and sub structures, you have everything you need to handle this easily. The text bounds should be sufficient for your needs.
P.S. Whenever properties of the text object are changed, the text object is processed / re-generated late in the update cycle and just before the frame is rendered. This means that if you were to change the text in Awake or Start and then check the textInfo or text bounds, these would not be correct given the text object hasn’t been processed yet. When you change a property of a text object and need to have it processed right away because for instance you want to check the bounds, you can use TMP_Text.ForceMeshUpdate() to force the object to be processed right away. This would result in those bounds and textInfo getting populated with valid data.