Реализация интерфейса с подписью вызова и методом, возвращающим «this» - PullRequest
2 голосов
/ 27 марта 2019

Предисловие: Наша команда работает над библиотекой, построенной поверх d3.Так как мы используем TypeScript, мы также используем типы d3 из DefiniteTyped.Следующий вопрос возникает при попытке работать с такими интерфейсами, как ScaleOrdinal и многими другими оттуда.


Предположим, у нас есть интерфейс, содержащий как сигнатуру вызова, так и дополнительные свойства:

export interface Foo<T> {
    // Let's pretend this will be the identity function
    (arg: T): T;

    // Let's pretend that this will be a no-op function
    // Note that this returns "this"    
    doFoo(): this;
}

Как мы можем реализовать такой интерфейс правильно и безопасным для типа способом [1]?После исследования я обнаружил следующие связанные вопросы, все из которых немного отличаются и / или довольно старые.Я хотел бы получить представление о том, что мы что-то упустили или стоит ли поднимать проблему с командой TypeScript здесь:

  1. Как заставить класс реализовать сигнатуру вызова в Typescript?
  2. TypeScript: реализовать интерфейс с подписью вызова и подписью конструктора
  3. TypeScript: реализовать интерфейс с подписью вызова и подписью индексации

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


¹ Ради вопроса я бы хотел, чтобы реализацияявно переформулируйте аннотации всех типов.

1 Ответ

1 голос
/ 27 марта 2019

В последних версиях машинописного текста (3.2 или 3.3 не уверены, какие именно), когда вы объявляете функцию, вы также можете назначить дополнительные свойства функции, и машинописный текст будет рассматривать их как определение этих свойств и не будет жаловаться на то, что они не были определены:

export interface Foo<T> {
    (arg: T): T;  
    doFoo(): this;
}

function foo(arg: number) : number {
    return arg
}
foo.doFoo = function <TThis extends typeof foo>(this: TThis): TThis { // no polymorphic this in simple functions
    return this
}

let o: Foo<number> = foo;  // foo is compatible with Foo<number>

Старый делал это, который все еще работает, использует Object.assign для создания функции с дополнительными свойствами:

let o: Foo<number> = Object.assign(function (arg: number): number {
    return arg
}, {
    doFoo: function <TThis>(this: TThis): TThis {
        return this
    }
})
...