Typescript - сделать свойства класса недоступными, пока пользователь не войдет в систему - PullRequest
0 голосов
/ 17 октября 2019

Я хочу, чтобы свойства моего основного класса были нулевыми до тех пор, пока пользователь не вызовет метод login(). Я не могу поместить это в конструктор, так как это асинхронный метод.

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

import api from "./api"
import {RSS, User} from "./endpoints"

type isLoggedIn<B extends boolean, T> = B extends true ? T : null

export default class MyApi<B extends boolean = false> {
    private loggedIn: B
    //This is needed for other properties, but you must login to get it
    private accessToken: string 
    public rss: isLoggedIn<B, RSS>
    public user: isLoggedIn<B, User> 
    //There are a lot more properties, but they generally look like this ^

    constructor(private clientId: string, private clientSecret: string) {}

    public login = async () => {
        const auth = await api.get("oauth url", {client_id: this.clientId, client_secret: this.clientSecret, grant_type: "client_credentials"})
        this.accessToken = auth.access_token

        //With the accessToken, the other properties can be initialized
        this.rss = new RSS(this.accessToken) as isLoggedIn<B, RSS>
        this.user = new User(this.accessToken) as isLoggedIn<B, User>

        this.loggedIn = true as B //???
    }

}

Основная проблема заключается в том, что универсальный тип в классе никогда не становитсяtrue, он всегда остается по умолчанию (false). Я не знаю, как бы это сделать после запуска функции login().

Ответы [ 2 ]

1 голос
/ 17 октября 2019

Вот решение, использующее только типы, оно зависит от повторного использования экземпляра, который вошел в систему,

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

type MyApiNoAuth = Omit<MyApi, Exclude<keyof MyApi, "login">>
class MyApi {
  private loggedIn = false;

  private constructor(private clientId: string, private clientSecret: string) { }
  static create(clientId: string, clientSecret: string): MyApiNoAuth {
    return new MyApi(clientId, clientSecret)
  }

  public login = () => {
    // do whatever you want here.
    return this; // needed to be last line here
  }

  public next = () => {
    return "next";
  }
  public othermethod = () => "";
}



const test = new MyApi(); // fails can't instantiate like this. (good)
const test1 = MyApi.create("clientId", "clientSecret"); // works good
const test2 = MyApi.create("clientId", "clientSecret").next(); // can't call this instance hasn't called login.
const test3 = MyApi.create("clientId", "clientSecret").login(); // this is the instance class we will use

test3.next() // great. works
test3.othermethod() // great works because we've logged in in this instance.
1 голос
/ 17 октября 2019

Этого можно добиться с помощью немного другого подхода.

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

Это может быть выполнено через защиту типов.

type IsLoggedIn<B extends boolean, T> = B extends true ? T : never;

export default class MyApi<B extends boolean = false> {
  isLoggedIn(): this is MyApi<true> {
    return this.loggedIn;
  }

  rss: IsLoggedIn<B, RSS>;
  user: IsLoggedIn<B, User>;
}

Учитывая вышесказанное, мы можем написать

async function useApi(api: MyApi<boolean>) {
  await api.login();

  if (api.isLoggedIn()) {
    api.user.// etc.
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...