Q:

Why are giving a union type to a variable and giving the same type to a parameter so different?

Using the tsc --strict command I get the following error:  

error TS2339: Property 'foo' does not exist on type 'T'.   Property
  'foo' does not exist on type 'Bar'. 16   console.log(obj.foo)

What I don't understand is why I can assign the object literal to obj but get an error using the same property inside the function. Thanks!
type Foo = {
  foo: string
  xyz: string
}

type Bar = {
  bar: string
  xyz: string
}

type T = Foo | Bar

let obj: T = { foo: "foo", xyz: "xyz" }

const sayHello = (obj: T) => {
  console.log(obj.foo)
}

A:

When you assign to a union you can assign either one of the constituent types from the union. This is why the assignment succeeds
When you try to access a parameter/variable of a union type, you don't actually know which of the union constituent types will actually be in it. It could be wither of them, so typescript considers as safe only access properties that are common to all members of the union. In your example accessing xyz is safe as it exists in both union constituents 
You need to use a type guard in order to get the compiler to narrow the type of the parameter to either one or the other constituent types:

const sayHello = (obj: T) => {
  console.log(obj.xyz) // ok common 
  if ('bar' in obj) {
    obj.bar // ok
  } else {
    obj.foo //ok
  }
}

Playground Link

