Good points!

Seems like for "6. Optional properties"

One should rather use tagged unions (see: Abstract Data Types, variants) that are usually written like this in TS:

    type Product = 
     | { type: 'digital', id: string, sizeInMb: number }
     | { type: 'physical', id: string, weightInKg: number }
At least I find it more elegant, concise and fun to work with :)
Also, for using type guards to validate incoming data, check out https://github.com/pelotom/runtypes.

Or if brave enough to dive into the deep end of FP, io-ts is nice. https://github.com/gcanti/io-ts