Почему тип функции не подходит для функционального интерфейса?

interface IGetObjectCallback {
    (data: any): void;
    (data: any, elapsedTime: number): void;
}

interface Fetcher extends IGetObjectCallback {
    getObject(done: IGetObjectCallback): void;
}
let a:Fetcher = ('data',3) => {
  
}

Playground Link

Почему при таком коде получаю ошибку несоответствия типов при присваивании?


Ответы (1 шт):

Автор решения: Grundy

Данный вопрос можно разбить на две части:

  1. как работает перегрузка в функциональном интерфейсе
  2. добавление в этот интерфейс метода

Как работает перегрузка в функциональном интерфейсе

Если в функциональном интерфейсе указано несколько перегрузок, как в примере в вопросе

interface IGetObjectCallback {
    (data: any): void;
    (data: any, elapsedTime: number): void;
}

Это значит, что функция должна удовлетворять обоим этим определениям.

В случае с

let a:IGetObjectCallback = ('data',3)=>{}

Передаваемая функция не совпадает ни с одним. Если добавить в определение типы

let a:IGetObjectCallback = (data:'data',elapsedTime:3)=>{}

Ошибка станет понятнее: тип 3 не совместим с типом number, так как по интерфейсу могут передать любое число, а функция может принять только 3.

Если заменить типа на number

let a:IGetObjectCallback = (data:'data', elapsedTime:number)=>{}

Все еще не будет соответствия интерфейсу, так как передаваемая функция принимает строго два параметра, тогда как в интерфейсе указано, что он должна уметь принимать и всего один параметр. В этом случае решить можно с помощью значения по умолчанию

let a:IGetObjectCallback = (data:'data', elapsedTime:number = 0)=>{}

Теперь передаваемая функция удовлетворяем всем условиям и присваивается без ошибок.


Добавление в этот интерфейс метода

Я не нашел нормального способа с помощью литерала создать функцию со статическим методом.

Поэтому пока единственный вариант, который я вижу - сделать наличие метода опциональным. В этом случае можно создать литерал функции без него и далее просто его присвоить:

Например:

let b: Fetcher = (data: any, elapsedTime: number = 0) => { console.log(data) }
b.getObject = (data: any, elapsedTime: number = 0) => { console.log(data) }

Интерфейс в этом случае будет выглядеть так:

interface Fetcher extends IGetObjectCallback {
  getObject?(done: IGetObjectCallback): void;
}
→ Ссылка