Как вернуть экземпляр класса на основе ключа? - PullRequest
1 голос
/ 09 мая 2020

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

Typescript : 3.8.3

Игровая площадка

Вот код:

abstract class BaseProvider {
  foo!: string
}

class ProviderA extends BaseProvider {
  public testA(): string {
    return this.foo + 'a'
  }
}

class ProviderB extends BaseProvider {
  public testB(): string {
    return this.foo + 'b'
  }
}

type Provider = ProviderA | ProviderB

const providers = {
  a: ProviderA,
  b: ProviderB,
}

function useProvider<T extends keyof typeof providers>(key: T): Provider {
  const defaultProvider = providers.a
  const providerByKey = providers[key]

  if (!providerByKey) {
    console.warn(`Provider "${key}" doesn't exists.`)
    return new defaultProvider()
  }

  return new providerByKey()
}

const providerA = useProvider('a')

/**
 * Property 'testA' does not exist on type 'Provider'.
 * Property 'testA' does not exist on type 'ProviderB'.
 */
providerA.testA()

const providerB = useProvider('b')

/**
 * Property 'testB' does not exist on type 'Provider'.
 * Property 'testB' does not exist on type 'ProviderA'.
 */
providerB.testB()

Я ожидаю:

useProvider('a'), чтобы вернуть new ProviderA() и получить доступ к метод testA.

useProvider('b'), чтобы вернуть new ProviderB() и получить доступ к методу testB.

Я нашел «решение», чтобы вернуть класс вместо экземпляра, но это не то, что мне нужно:

function useProvider<T extends keyof typeof providers>(key: T): typeof providers[T] {
  return providers[key]
}

const providerA = new (useProvider('a'))()
providerA.testA()

1 Ответ

2 голосов
/ 09 мая 2020

Вы довольно близки к решению, вам просто нужно указать связь между типом возвращаемого значения и T. Тип возврата будет типом экземпляра класса, расположенного в параметре providers в ключе T, поэтому InstanceType<typeof providers[T]>

Единственная проблема в том, что InstanceType<typeof providers[T]> не ясно для компилятора. то же самое, что возвращается new providerByKey(), поэтому вам придется либо использовать утверждение типа, либо переместить специализированный тип возврата в выделенную подпись publi c, сохраняя при этом вашу более разрешительную подпись для подписи реализации, как я сделал ниже . Обратите внимание, что хотя этот подход не использует утверждения типа, это означает, что вы сами по себе можете гарантировать, что то, что вы возвращаете, действительно согласуется с более сложной подписью publi c)

function useProvider<T extends keyof typeof providers>(key: T): InstanceType<typeof providers[T]>
function useProvider<T extends keyof typeof providers>(key: T): Provider {
  const defaultProvider = providers.a
  const providerByKey = providers[key]

  if (!providerByKey) {
    console.warn(`Provider "${key}" doesn't exists.`)
    return new defaultProvider()
  }

  return new providerByKey()
}

Ссылка на игровую площадку

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