Объявить тип делегата в Typescript
Исходя из фона С#, я хочу создать тип данных, который определяет подпись функции. В С# это delegate
объявлено следующим образом:
delegate void Greeter (string message);
public class Foo
{
public void SayHi (Greeter g) {
g("Hi!");
}
}
Теперь я хочу добиться аналогичного в Typescript. Я знаю, что Typescript не имеет типов делегатов, а только лямбда. Я придумал что-то вроде этого:
class Foo {
SayHi (greeter: (msg: String) => void) {
greeter('Hi!');
}
}
Пока это работает, я хочу повторно использовать подпись метода (msg:String) => void
пару раз и думаю, что было бы проще создать собственный тип - как делегат в С#.
Любые идеи, как это можно сделать?
Ответы
Ответ 1
В TypeScript интерфейсы могут иметь сигнатуры вызовов. В вашем примере вы можете объявить его следующим образом:
interface Greeter {
(message: string): void;
}
function sayHi(greeter: Greeter) {
greeter('Hello!');
}
sayHi((msg) => console.log(msg)); // msg is inferred as string
Ответ 2
Вы можете создать что-то вроде делегата, используя псевдоним типа:
type MyDelegate = (input: string) => void;
который определяет имя типа для указателя на функцию, как делегаты в С#. В следующем примере он используется в сочетании с параметрами универсального типа:
type Predicate<T> = (item: T) => boolean;
export class List<T> extends Array<T> {
constructor(...items: T[]){
super();
for(let i of items || []){
this.push(i);
}
}
public hasAny(predicate?: Predicate<T>): boolean {
predicate = predicate || (i => true)
for(let item of this) {
if(predicate(item)) return true;
}
return false;
}
}
Ответ 3
Спустя пять лет, многие, многие версии TS, я обнаружил, что использую более простое определение type
для объявления типов функций:
type Greeter = (msg: string) => void;
const someGreeter: Greeter = (msg: string) => 'Hi there with ${msg}';
Ответ 4
Определение типа для вызываемого выражения (это черновик ok, для людей... не BNF или ничего формального):
callableType: (paramsDef) => returnType
paramsDef: MULTIPLE paramDef SEPARATED BY ,
paramDef: EITHER paramName: paramType
OR optionalParamName?: paramTypeWhenDefined
OR ...manyParamName: eachParamType[]
Пример:
var func = something as ((...x: any[]) => any);
Затем вы можете:
var result = func("a", "b", 2);
Ответ 5
Теперь я публикую и использую @steelbreeze/delegate; он имеет несколько ограничений по сравнению с делегатом С#, поскольку он неизменен, но в остальном работает хорошо (и когда он вызван возвращает результаты от всех вызванных функций).
Он позволяет писать код, например:
import { create as delegate } from "@steelbreeze/delegate";
function world(s: string) {
console.log(s + " world");
}
const one = delegate(s => console.log(s + " Hello world"));
const two = delegate(s => console.log(s + " Hello"), world);
one("A");
two("B");
delegate(one, two)("C");