reactjs - Typescript `typeof React.Component` não estende a interface? Problema ao definir componente de ordem superior
Estou criando um componente de ordem superior para envolver um componente que estende a interface:
interface ClickOutsideInterface {
onClickOutside: (e: Event) => void
}
A fábrica que eu criei espera um React.ComponentClass que implemente a ClickOutsideInterface:
function clickOutside<P>(Component: React.ComponentClass<P> & ClickOutsideInterface){
return class ClickOutside extends React.Component<P, {}> {
/* on click outside invoke Component.onClickOutside */
render() {
return(<div><Component {...this.props} /></div>)
}
}
}
Para testar a fábrica, implementei um Componente que estende a ClickOutsideInterface
class Test extends React.Component<TProps, TState> implements ClickOutsideInterface {
onClickOutside(event: Event): void {
this.setState({
closed: true
})
}
render(){
return(
<div>{this.state.closed}</div>
)
}
}
Mas quando eu uso o componente como um argumento na função clickOutside:
const withClickOutside = clickOutside(Test)
Eu recebo o seguinte erro de tipo para o argumento Test:
O argumento do tipo 'typeof Test' não é atribuível ao parâmetro do tipo 'ComponentClass & ClickOutsideInterface'. O tipo 'typeof Test' não é atribuível ao tipo 'ClickOutsideInterface'. A propriedade 'onClickOutside' está ausente no tipo 'typeof Test'.
Alguma ideia de por que o Typescript acredita que eu não estou implementando a interface em Test?
Resposta #1
O TypeScript diz que você não implementou a interface que sua função exige de seu argumento porque você de fato não implementou.
Quando você escreve
class A {
//...
}
Você define dois tipos e um valor.
O valor, que é chamado A, é a classe. É a função que você chama com new para criar objetos.
O primeiro tipo, que também é chamado de A, é o tipo dos objetos que são criados ao chamar a função de classe com new conforme descrito acima.
O segundo tipo é o tipo daquela função de classe. Declarar uma classe não cria automaticamente um nome para esse tipo, mas o tipo existe mesmo assim porque todos os valores têm um tipo. Esse tipo é escrito typeof A porque é o tipo do valor A, o tipo da classe.
Portanto, dependendo do que você está tentando realizar, você precisa ou
Passe uma instância de Test
const withClickOutside = clickOutside(new Test);
Ou altere sua função para que ela receba um objeto correspondente ao tipo da própria classe, e não aos objetos que ela cria
function clickOutside<P>(
Component: new () => React.ComponentClass<P> & ClickOutsideInterface
) {...}
Suspeito que seja o último que você quer neste caso.
Por último, embora você possa querer isso para fins de documentação, o que é completamente válido, gostaria de notar que não há razão para realmente declarar que sua classe implementa a interface. TypeScript é uma linguagem com tipagem estrutural e todas as interfaces são implementadas ao ter membros compatíveis.
