Reads REP-2011 type hashes from ROS-generated type description JSON files.
The JSON contains the canonical hash generated by ROS. Reading it is intentional: hashing the source text directly is not REP-2011 compatible.
@spec calculate_type_hash(struct()) :: {:ok, String.t()} | {:error, term()}
@spec type_hash(String.t(), String.t()) :: {:ok, String.t()} | {:error, atom() | tuple()}
@spec type_hash!(String.t(), String.t()) :: String.t()