You are looking for "cross tabulation" or a "pivot table". I added tags.
However:
if I don't know how many types are there, and can't specifically list all cases, how can I achieve it?
Basically, that's impossible in a single SQL query because SQL demands to know the number of result columns at call time. It cannot return a dynamic number of columns on principle.
There are various workarounds with polymorphic types, or with a document type like json, jsonb, hstore or xml, or return arrays instead of individual columns ...
But to get exactly what you are asking for, an unknown number of dedicated columns, you need a two-step workflow. Like:
- Build the query dynamically (determining the return type).
- Execute it.
Related:
That said, if your case is simple and you deal with a hand full of known types, you can just over-provision. With a faster crosstab() query, or with simple conditional aggregation like you have it, just more elegant and efficient with the aggregate FILTER clause:
SELECT count(*) FILTER (WHERE type = 'A') AS type_a
     , count(*) FILTER (WHERE type = 'B') AS type_b
     , count(*) FILTER (WHERE type = 'C') AS type_c
     , count(*) FILTER (WHERE type = 'D') AS type_d
     -- that's all folks!
FROM   tbl;
Types with no entries report 0 (count() never returns NULL) which would be correct anyway.
Does not work for unknown types, obviously.