Reputation: 966
I have a function that receives two arguments, a job and an employee. The employee is optional: if the job is scheduled, the employee will be there, otherwise it is not needed.
type Job = {
name: string;
schedule?: string;
}
type WorkingEmployee = {
doWork: (jobName: string) => void
}
function f(job: Job, employee?: WorkingEmployee){
if (job.schedule) {
if (employee) {
employe.do(job.name)
}
}
}
However, I know more than this. I know that, if the job is scheduled, then the employee will be there. So I want to enforce this and take advantage of this knowledge:
type ScheduledJob = {
task: string;
isDoable: string;
}
type Employee<T> = T extends ScheduledJob ? WorkingEmployee : undefined;
function f<T extends Job>(job: T, employee: Employee<T>){
if (job.schedule) {
employee.doWork(job.name);
}
}
But typescript does not take it: "Object is possibly undefined"
, referring to employee.doWork
. Why does it not accept it? If schedule
is there, then we know for certain that employee
is not undefined
.
My questions are: 1. Why the compiler does not accept this code? 2. Is there any way of achieving what I am trying to do here?
Upvotes: 0
Views: 93
Reputation: 138257
Generic types are narrowed down when the function gets called. At the time of definition you only know that T
is some sort of Job
. The typeguard will narrow down the type of job
, it won't change what T
refers to.
let a: T, b: T;
if(a.narrow) {
// a can be narrowed down, but it is unknown wether the same applies to b. Thus T cannot be narrowed.
}
You could overload f though (not sure if that works as intended, however it is clearer than a generic function with conditional types):
function f(job: ScheduledJob, employee: WorkingEmployee);
function f(job: Job, employee?: WorkingEmployee) {
//...
}
Upvotes: 1