Poor programmers dive into methods and algorithms, and then try to force their data to match. Which almost never works.
I value plain, simple code and equally plain, simple writing. I am becoming dismayed at the trend towards fancy labels on basic things. A while back someone talked about 'affordances' in C# which sent me into a tailspin because I thought there was some significant area of the language I'd never encountered. Turns out he just meant attributes and methods.
So we've got a tree (the AST), we've got a symbol table for the current scope (a hash table of <id, info> pairs), and we have a stack of symbol tables (a stack).
A tree, a hash table and a stack. Those are data structures. What more needs to be added to this definition to turn it from "data structures" into a "data model"?
Firstly this is a serious question, secondly I have a great deal of experience of defining data structures to solve problems, so I can't see what adding an abstract term is doing.
You could say that the extra something is the specification/maintenance of the correct interrelationship between those data structures (and I'd agree), and there's a word for that: it's called 'code'. I genuinely don't understand what you're getting at and I'd genuinely like to know.
I'll give you an example from a ongoing side project of mine: https://github.com/SuperCuber/facto_rs/blob/master/src/model...
Hopefully the Rust syntax is not too much of a distraction here, but enough to focus on the `struct` and `enum` parts (an enum in rust can be "one of" the variants, like tagged union or sum type in other languages, or | operator in typescript). The project is a live wallpaper/screensaver that is a simulation of something like a combination of the games Factorio and Mini Metro.
I had in mind what I wanted to happen - a grid containing a rail network with trains running between different nodes.
What I call the model is the representation of the things in the code: I could store the train's position in terms of [float,float] and a facing Direction, but instead I choose to store it in terms of List<[int, int]> of grid tiles that it plans to go through, then an int for its current position in the list, and then a single float between 0 and 1 representing how far into the tile it's moving.
The two possible solutions have pros and cons, and there are other solutions as well that are equally valid I'm sure. In my mind, the process of "modeling your domain/problem space" is about deliberately thinking about these things and choosing what you think is the best.