Search code examples
typescripttypechecking

Extracting string literal values from union type for stronger type checking


I have the following types:

interface Employee {
    employeeType: string
}

interface Manager extends Employee   { employeeType: 'MANAGER'   // .. etc }

interface Developer extends Employee { employeeType: 'DEVELOPER' // .. etc }

type Staff = Developer | Manager

I want to create a new dynamic type that holds all possible string literals for Staff > employeeType, such that if a new Employee type is added to Staff union, their employeeType is added to that new type.

For example, if that type was defined and used manually it could be:

type EmployeeType = 'DEVELOPER' | 'MANAGER'

I would like to be able to add new type of Employee interface and update the Staff union, and have the EmployeeType dynamically include the new type, e.g. -

...
interface Designer extends Employee { employeeType: 'DESIGNER' // ..etc }

type Staff = Developer | Manager | Designer

// ... now EmployeeType contains 'DEVELOPER' | 'MANAGER' | 'DESIGNER'

The advantage here is to be able to enforce strong type checking when doing something like this:

function createEmployee(employeeType: EmployeeType, attributes: ...) {
   // ...
}

As opposed to using employeeType: string as the input.

Is there a way to accomplish this in typecript? Here's the relevant Typescript Playground :)


Somewhat related question (albeit using Enums): https://stackoverflow.com/a/52396706/187907


Solution

  • You can just lookup employeeType property, as it is a common property of Staff:

    type EmployeeType = Staff["employeeType"] // "DEVELOPER" | "MANAGER" | "DESIGNER"
    
    createEmployee('MANAGER') // works
    createEmployee('SALES')   // error
    

    Sample