Search code examples
typescripttypesconstraintsfieldunion

Typescript: Constraint on a field of an union type


I created a union type of objects. They all have a field role to differentiate them. Here we have teacher and student:

type User =
    {
        role: "student";
        followClasses: string[];
    } |
    {
        role: "teacher";
        since: number;
    };

Then I wanted to create a function to generate a default student:

const defaultStudent = (): User => ({
    role: "student",
    followClasses: [],
});

But since the return type is the union type User, typescript doesn't know that it's a student, and throw me a warning when I type this:

const student = defaultStudent();

console.log(student.followClasses);
//          Warning here ⮥

How to make the function defaultStudent have a constrained return type (student)?


Solution

  • Extract the two members of the unions as individual types

    type Student = {
      role: "student"
      followClasses: string[]
    }
    
    type Teacher = {
      role: "teacher"
      since: number
    }
    

    and define your union from them directly

    type User = Student | Teacher
    

    At this point, you can say that your defaultStudent function doesn't just return a User, you can be more precise than that. It returns a Student.

    const defaultStudent = (): Student => ({
      role: "student",
      followClasses: [],
    })
    
    const student = defaultStudent()
    console.log(student.followClasses) // <-- OK