Почему typescript не выводит фактический тип условной привязки с помощью аргумента вложенного типа?

#typescript #type-inference

#typescript #вывод типа

Вопрос:

В следующем фрагменте почему typescript не выводит фактический F тип в качестве возвращаемого типа функций, а выводит его только как bound ( GenericPerson ), у которого нет свойства ‘address’ ?

 type GenericPerson = { name: string; };
type GenericCompany<X extends GenericPerson> = { companyName: string; employees: X[]; };

const getEmployeeDetails= <F extends GenericPerson, T extends GenericCompany<F>>(company: T): F[] => {
  return company.employees;
};

getEmployeeDetails({
  companyName: 'XYZ',
  employees: [
    {
      name: 'John',
      address: 'London',
    }
  ],
}).map((x) => {
  console.log(x.address); // Property 'address' does not exist on type GenericPerson
});
 

[Игровая площадка]

Я могу это исправить, явно указав аргументы типа

 type ExtendedPerson = {name: string; address: string};
getEmployeeDetails<ExtendedPerson, GenericCompany<ExtendedPerson>>({
  companyName: 'XYZ',
  employees: [
    {
      name: 'John',
      address: 'London',
    }
  ],
}).map((x) => {
  console.log(x.address); // Type-checks.
});
 

[Игровая площадка]

Или с помощью условного с infer (где я должен вставить приведение)

 type InferMe<T extends GenericCompany<any>> = T extends GenericCompany<infer R> ? R : never;

function getEmployeeDetails<F extends GenericPerson, T extends GenericCompany<F>>(company: T): InferMe<T>[] {
  return company.employees as InferMe<T>[];
}
 

[Игровая площадка]

Вопрос: Есть ли причина для этого? / Есть ли способ обойти это без приведения и без принуждения вызывающего абонента явно указывать аргументы?

Ответ №1:

Это должно выполнить работу:

 function getEmployeeDetails<F extends GenericPerson>(company: GenericCompany<F>): F[] {
    return company.employees;
}

getEmployeeDetails({ companyName: 'XYZ', employees: [{ name: 'John', address: 'London' }], })
    .map(x => console.log(x.address)); // property 'address' recognized correctly.
 

Ответ №2:

Вам не нужна F переменная универсального типа, ее можно упростить:

 const getEmployeeDetails = <T extends GenericCompany<GenericPerson>>(company: T): T['employees'] => {
  return company.employees;
};