Create new columns depending on the columns in a table
Seems like there are up to two rows for f and one for b.

In that case you can simplify it to a single GROUP BY using conditional aggregation:

SELECT legacy_id,
   -- first number 'f'
   Min(CASE WHEN phone_type = 'f' THEN phone_number END) AS f_phone_number_1,
   -- first number 'b'
   Min(CASE WHEN phone_type = 'b' THEN phone_number END) AS b_phone_number_1,
   -- when MIN and MAX are different return the 2nd number
   NullIf(Max(CASE WHEN phone_type = 'f' THEN phone_number END)
         ,Min(CASE WHEN phone_type = 'f' THEN phone_number END)) AS f_phone_number_2
FROM table
GROUP BY 1


Edit: 

Of yourse you can't use the MAX/MIN approach when there's more than two rows per type.

But you can reduce the ranks down to one and move the case to the outer select:

SELECT legacy_id,
   Max(CASE WHEN phone_type = 'f' AND rn = 1 THEN phone_number END) AS f_phone_number_1,
   Max(CASE WHEN phone_type = 'f' AND rn = 2 THEN phone_number END) AS f_phone_number_2,
   Max(CASE WHEN phone_type = 'f' AND rn = 3 THEN phone_number END) AS f_phone_number_3,
   Max(CASE WHEN phone_type = 'f' AND rn = 4 THEN phone_number END) AS f_phone_number_4,
   Max(CASE WHEN phone_type = 'b' AND rn = 1 THEN phone_number END) AS b_phone_number_1,
   Max(CASE WHEN phone_type = 'b' AND rn = 2 THEN phone_number END) AS b_phone_number_2,
   Max(CASE WHEN phone_type = 'b' AND rn = 3 THEN phone_number END) AS b_phone_number_3,
   Max(CASE WHEN phone_type = 'b' AND rn = 4 THEN phone_number END) AS b_phone_number_4
FROM 
 (
   SELECT legacy_id,
      phone_type,
      phone_number,
      Dense_Rank() 
      Over (PARTITION BY a.legacy_id, a.phone_type 
            ORDER BY a.phone_number) AS rn
   FROM tab
 ) AS dt
GROUP BY 1