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

Объявить тип делегата в 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 пару раз и думаю, что было бы проще создать собственный тип - как делегат в С#.

Любые идеи, как это можно сделать?

4b9b3361

Ответ 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");