The type in your question is not, in usual sense, discriminated union - your union members don't have common, non-optional literal property called discriminant.
So, as @Alex noted in his answer, your union is somewhat similar to
type Person = {
fullName?: string
firstName?: string
lastName?: string
}
so it can be initialized with { firstName: 'test' }
With true discriminated unions, you get back the logic for checking non-optional properties, as well as checking that object literal may only specify known properties:
interface FullName {
kind: 'fullname';
fullName?: string
}
interface Name {
kind: 'name';
firstName: string
lastName: string
}
type Person = FullName | Name;
const p1: Person = {kind: 'fullname'}; // ok
const p2: Person = {kind: 'fullname', fullName: 'test' }; // ok
checking non-optional property:
const p3: Person = {kind: 'name', firstName: 'test' };
error:
Type '{ kind: "name"; firstName: string; }' is not assignable to type 'Person'.
Type '{ kind: "name"; firstName: string; }' is not assignable to type 'Name'.
Property 'lastName' is missing in type '{ kind: "name"; firstName: string; }'.
checking extra property:
const p5: Person = { kind: 'fullname', bar: 42 }
error:
Type '{ kind: "fullname"; bar: number; }' is not assignable to type 'Person'.
Object literal may only specify known properties, and 'bar' does not exist in type 'Person'.
However, as @JeffMercado found out, type checking is still a bit off:
const p6: Person = { kind: 'fullname', firstName: 42 }; // no error. why?
I'd consider posting an issue for typescript github project.