Because transactions are identified by their hashes. Transaction hash is calculated on all the fields of the transaction. After transaction is signed, you can't modify it without changing the hash, and if you do that before it is mined, the network takes it as a different transaction.
When a transaction creates a contract, the contract address is stored in the Receipt. How would you add this data to the transaction
struct without changing its hash? You couldn't. The only way to seal the result of the transaction is to create another
struct and store it there. This is what
Receipts are, its the
output of the transaction, a very different concept, while
Transaction data being the
In short, the decision to design things this way was correct.
BTW, transactions are not stored in the block header, transactions are stored in a separate trie. Only the hash of all transactions of the block is kept in the header.