[Dica] Como obter a tipagem de um método sem instanciar a classe com TypeScript
Ok, é um tema bem específico. Mas deicidi compartilhar pois quando um tema é muito específico, geralmente é mais difícil de encontrar conteúdo sobre ele. Então vamos começar...
Em qual situação você pode se deparar com esse problema? 💣
No meu caso, eu estava trabalhando com NestJs e usando um módulo de comunicação entre microsserviços com RabbitMQ. Uma característica é que usando uma abordagem de comunicação como essa, não há como o saber o retorno da função, afinal, quem fará a chamada do método do controller será o próprio RabbitMQ dependendo da routing key usada.
Dica de uso para esses casos 🔥
// Aqui eu defino uma classe, que simboliza o controller
class Animal {
name: string
constructor(name: string) {
this.name = name
}
setName(name: string) {
this.name = name
return this
}
makeSound(sound: string, repeat: boolean) {
console.log(sound)
if (repeat) console.log(sound)
}
}
// O tipo MethodGetter é responsável por obter a tipagem do método K de uma determinada classe T
type MethodGetter<T, K extends keyof T> = T[K] extends (...args: any) => any
? T[K]
: any
// O tipo MethodParameter é responsável por obter os argumentos do método K de uma determinada classe T
type MethodParameters<T, K extends keyof T> = Parameters<MethodGetter<T, K>>
// O tipo Args é responsável por permitir a adição de outros parâmetros, além dos próprios parâmetros inferidos pelo método K
type Args<T, K extends keyof T> = [...MethodParameters: MethodParameters<T, K>, aditionalTypings?: any]
// O tipo Return é responsável por obter o retorno do método K de uma determinada classe T
type Return<T, K extends keyof T> = ReturnType<MethodGetter<T, K>>
// A classe messageService simboliza algum módulo de comunicação, como o que eu mencionei acima
class messageService {
static sendAwait<T, K extends keyof T>(
routingKey: string,
...args: MethodParameters<T, K>
): Return<T, K> {
const res = ('routingKey' + routingKey + 'args:' +
args) as unknown as Return<T, K>
return res
}
}
const { name } = messageService.sendAwait<Animal, 'setName'>('animal@set_name', 'Gatinho Tom')
Tipagem em ação ✨
Note que ao passar a classe Animal, mesmo sem instanciá-la, e indicar o método que será chamado, o TypeScript é capaz de inferir corretamente os argumentos e o retorno da função especificada.
Outras dicas 🚀
Se você curtiu esse post, não deixe de conferir a documentação oficial do TypeScript sobre Utility Types, Indexed Access Types, Keyof Type Operator, que me ajudaram muito, além do TypeScript playground para você poder treinar na Web.