Свободный API с TypeScript? - PullRequest
       17

Свободный API с TypeScript?

0 голосов
/ 06 августа 2020

Я пытаюсь разработать свободный API-интерфейс на TypeScript, который я хотел бы использовать следующим образом:

export interface Person {
    firstName: string;
    lastName: string;
}

new Builder<Person>()
    .func1("stringArg1")
    .func2("firstName")
    .func3("stringArg2");

func2 может принимать только имена свойств, которые фактически встречаются в указанном интерфейсе (здесь : Person). Кроме того, func2 должен быть доступен только при возвращаемом значении func1 и func3 только при возвращаемом значении func2. В любом случае необходимо соблюдать последовательность вызовов функций. Класс Builder должен иметь возможность оценивать указанные значения в любое время (stringArg1, firstName и stringArg2).

Буду очень благодарен за советы и помощь.

Ответы [ 2 ]

1 голос
/ 06 августа 2020

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

class Builder<T> {
    func1 = (f1arg: string) => ({
        func2: (f2arg: keyof T) => ({
            func3: (f3arg: string) => ({
                // something here?
            })
        })
    })
}

Здесь, хотя мы не поддерживаем единственный экземпляр класса Builder. Как только вы вызываете func1(), вы получаете новый объект со свойством func2. Когда все будет готово, func3() может вернуть все, что вы хотите (и он имеет доступ к аргументам из-за того, что они закрыты), включая экземпляр Builder, если хотите. В зависимости от того, что вы ищете, это может сработать.

Более нормальным случаем класса Builder является то, что после каждого метода возвращается один и тот же экземпляр этого класса. Это достаточно легко написать, если у вас нет ограничений на то, какие методы и когда можно вызывать. Если у вас есть такие ограничения, вы можете сообщить об этом компилятору, но это выглядит немного сложно. Вот один из возможных способов сделать это:

type Builder0<T> = Omit<_Builder<T>, "func2" | "func3">;
type Builder1<T> = Omit<_Builder<T>, "func1" | "func3">;
type Builder2<T> = Omit<_Builder<T>, "func1" | "func2">;
type Builder<T> = Omit<_Builder<T>, "func1" | "func2" | "func3">;
class _Builder<T> {
    f1arg?: string;
    f2arg?: keyof T;
    f3arg?: string;
    func1(f1arg: string): Builder1<T> {
        this.f1arg = f1arg;
        return this;
    }
    func2(f2arg: keyof T): Builder2<T> {
        this.f2arg = f2arg;
        return this;
    }
    func3(f3arg: string): Builder<T> {
        this.f3arg = f3arg;
        return this;
    }
}
const Builder: new <T>() => Builder0<T> = _Builder;

В этом случае каждый метод возвращает this, а во время выполнения это просто «нормальный» -i sh свободный интерфейс. Но компилятор увидит new Builder<Person>() как что-то, что производит не Builder<Person>, а Builder0<Person>, что (если вы посмотрите на тип), то же самое, что и конструктор, но использует Omit для предотвращения доступа кода TS к его методу func2 или func3. Если вы вызываете func1(), он возвращает Builder1<Person>, что предотвращает доступ кода TS к его методам func1 или func3. Итак, когда вы вызываете func1(), за которым следует func2(), за которым следует func3(), компилятор принимает Builder0 и возвращает Builder1, который возвращает Builder2, который, наконец, возвращает Builder, который пропускает все эти методы.

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

Надеюсь, один из этих подходов даст вам некоторые идеи. Удачи!

Детская площадка ссылка на код

1 голос
/ 06 августа 2020

Я точно не знаю, чего вы пытаетесь достичь, но вот вам go пример свободного API

export interface Person {
  firstName: string;
  lastName: string;
}

class Builder<T> {
  private func1Value?: string;
  private func2Value?: keyof T;
  private func3Value?: string;

  func1(arg: string): this {
    this.func1Value = arg;

    return this;
  }

  func2(key: keyof T): this {
    this.func2Value = key;

    return this;
  }

  func3(arg: string): this {
    this.func3Value = arg;

    return this;
  }
}

new Builder<Person>().func1('stringArg1').func2('firstName').func3('stringArg2');
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...