The Shell's Job, The Command's Job

Before the command sees it, the shell expands * into every matching file
Before the command sees it, the shell expands * into every matching file

When you type ls *.txt, the string *.txt isn't passed to ls as-is. The shell expands *.txt into actual filenames first, then hands ls file1.txt file2.txt notes.txt to ls.

In other words, ls has no idea it was called with a wildcard. The reason globs work with cp, mv, rm, and every other command is that expansion is the shell's job, not the command's.

That's also why, when no files match, bash passes the pattern through as a literal string, and ls *.xyz gives you a "file not found" error. zsh, by default, stops before ls ever runs and reports "no matches found" itself.