Подтвердить что ты не робот

Внедрение интерфейса TypeScript с сигнатурой голой функции и другими полями

Как написать класс, который реализует этот интерфейс TypeScript (и поддерживает компилятор TypeScript):

interface MyInterface {
    (): string;
    text2(content: string);
}

Я видел этот ответ: Как заставить класс реализовать подпись вызова в Typescript?

Но это работает только в том случае, если интерфейс имеет только голой функции. Это не работает, если у вас есть дополнительные члены (такие как функция text2), которые будут реализованы.

4b9b3361

Ответ 1

Класс не может реализовать все, что доступно в интерфейсе typescript. Два простых примера являются вызываемыми сигнатурами и индексами, например.: Внедрить индексируемый интерфейс

Причина в том, что интерфейс в первую очередь предназначен для описания всего, что могут сделать объекты JavaScript. Поэтому он должен быть действительно надежным. Класс typescript, однако, предназначен для того, чтобы представлять специфическое наследование прототипа в более обычном/легко понятном или легком в использовании способе OO.

Вы все равно можете создать объект, следующий за этим интерфейсом:

interface MyInterface {
    (): string;
    text2(content: string);
}

var MyType = ((): MyInterface=>{
  var x:any = function():string { // Notice the any 
      return "Some string"; // Dummy implementation 
  }
  x.text2 = function(content:string){
      console.log(content); // Dummy implementation 
  }
  return x;
}
);

Ответ 2

Здесь вы найдете описание принятого ответа.

Насколько я знаю, единственный способ реализовать сигнатуру вызова - использовать функцию/метод. Чтобы реализовать оставшиеся элементы, просто определите их для этой функции. Это может показаться странным разработчикам из С# или Java, но я считаю это нормальным в JavaScript.

В JavaScript это было бы просто, потому что вы можете просто определить функцию, а затем добавить ее. Однако система типа TypeScript не позволяет этого, потому что в этом примере Function не определяет член text2.

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

//A closure is used here to encapsulate the temporary untyped variable, "result".
var implementation = (() => {
    //"any" type specified to bypass type system for next statement.
    //Defines the implementation of the call signature.
    var result: any = () => "Hello";

    //Defines the implementation of the other member.
    result.text2 = (content: string) => { };

    //Converts the temporary variable to the interface type.
    return <MyInterface>result;
})(); //Invokes the closure to produce the implementation

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

Вот что я считаю более реалистичным:

interface TextRetriever {
    (): string;
    Replace(text: string);
}

function makeInMemoryTextRetriever(initialText: string) {
    var currentText = initialText;
    var instance: any = () => currentText;
    instance.Replace = (newText: string) => currentText = newText;

    return <TextRetriever>instance;
}

var inMemoryTextRetriever = makeInMemoryTextRetriever("Hello");

Ответ 3

Там простой и безопасный способ сделать это с ES6 Object.assign:

const foo: MyInterface = Object.assign(
  // Callable signature implementation
  () => 'hi',
  {
    // Additional properties
    text2(content) { /* ... */ }
  }
)

Типы пересечений, которые, как я думаю, не были доступны в TypeScript, когда этот вопрос изначально был задан и ответил, являются секретным соусом для правильного ввода текста.