Tree-sitter is more general: it aims to provide support for many languages and so its bash support is lacking a little. But it's very fast. It's designed for IDEs (hence why bash-lsp is using it). It caches its results and only re-parses on newly changed code blocks.
sh by mvdan and shellcheck are both built specifically for the shell. They both have really robust grammar. shellcheck is great for error handling. sh is great for building ASTs (it's more of a true parser)
As always, it depends on your use case. If you need a descriptive summary of errors / warnings in a shell script and performance isn't crucial, use shellcheck. If you need a really robust parser and AST output, use sh. If performance is crucial and/or you eventually want to support different languages, use tree-sitter.
Please feel free to jump in if I am wrong here!