Definitelytyped: Problema com connect() em @types/react-redux introduzido em 4.4.41

Criado em 6 jun. 2017  ·  44Comentários  ·  Fonte: DefinitelyTyped/DefinitelyTyped

Usando @types/react-redux versão 4.4.40, o código a seguir

import * as React from 'react';
import {connect} from "react-redux";

interface State {
    y: number;
}

// Own properties
interface OP {
    x: number;
}

// State properties
interface SP {
    y: number;
}

function mapStateToProps(state: State, ownProps: OP): OP & SP {
    return {
        x: ownProps.x,
        y: state.y,
    };
}

class TestComp extends React.Component<OP & SP, null> {
    render() {
        return <p>Hello</p>;
    }
}

export default connect(mapStateToProps)(TestComp);

me deixaria usar TestComp da seguinte forma:

const tc = <TestComp x={42}/>;

Com a versão 4.4.41 e 4.4.42 o acima leva ao seguinte erro de compilação:

error TS2324: Property 'y' is missing in type 'IntrinsicAttributes & IntrinsicClassAttributes<Component<OP & SP, ComponentState>> & { children?:...'.

/cc @thasner @seansfkelley @tkqubo @blakeembrey @sandersn @mhegazy @andy-ms @hans-permana

Comentários muito úteis

Quebra novamente no Typescript 3.0.1. Olá Thiene!

Todos 44 comentários

Estou recebendo esse erro também. Parece que um dos typedefs acidentalmente trocou TOwnProps e TMergedProps / TStateProps , mas eu só dei uma olhada superficial em index.d.ts .

Alguma atualização sobre este assunto? Eu acho que pode ser um showtopper para o novo desenvolvedor que vem para redux + typescript, obrigado pelo ótimo trabalho.

@brauliodiez Eu mesclei a correção #16969 de @blakeembrey. Deve estar disponível em uma hora ou mais. Deixe-me saber se isso ajuda.

Acho que ainda estamos vendo esse problema, mesmo com as correções de https://github.com/DefinitelyTyped/DefinitelyTyped/pull/16969. Aqui está um componente fictício que fiz para tentar isolar o problema:

import * as React from "react"
import { connect, MapStateToProps, MapDispatchToPropsFunction } from "react-redux"


interface RootState {
  globalA: string
  globalB: number
}

interface DumbComponentProps {
  a: string
  b: number
  c?: number
}

const DumbComponent = (props: DumbComponentProps): JSX.Element => {
  return (
    <div>Something: {props.a} {props.b} {props.c}</div>
  )
}

type ConnectedStateProps = Pick<DumbComponentProps, "a" | "b">
type ConnectedOwnProps = Pick<DumbComponentProps, "c">

const mapStateToProps: MapStateToProps<ConnectedStateProps, ConnectedOwnProps> = (
    state: RootState): ConnectedStateProps => {
  return {
    a: state.globalA,
    b: state.globalB
  }
}

const SmartComponent = connect(
  mapStateToProps
)(DumbComponent)

export default SmartComponent

Eu então uso SmartComponent em algum lugar e passo em c (observe que a & b devem vir do estado).

...
return (
  <SmartComponent c{2} />
)

O erro que recebo é:

error TS2322: Type '{ c: 2; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes<Component<DumbComponentProps, ComponentState>> & R...'.
  Type '{ c: 2; }' is not assignable to type 'Readonly<DumbComponentProps>'.
    Property 'a' is missing in type '{ c: 2; }'.

Inspecionando os tipos no VS Code, noto que está pegando o tipo errado para SmartComponent. Ele pensa que é React.ComponentClass<DumbComponentProps> ... mas deve ser React.ComponentClass<Pick<DumbComponentProps, "c">> (ou seja, deve aceitar apenas OwnProps. Isso faz sentido a partir dos tipos, onde ComponentDecorator é uma função que retorna um ComponentClass<T> (onde T extends TOwnProps ) ... então infelizmente não sei porque não está mapeando corretamente.

Estou fazendo algo obviamente errado aqui? Existe uma maneira de fazer com que o compilador me mostre passo a passo o que está inferindo?

Parece que mapDistpachToProps não é opcional agora. Está tudo bem ou é um bug?

Uma atualização para meu comentário acima, depois de pesquisar um pouco - criei um caso de teste que atualmente falha (mas acredito que não deveria) e uma correção para os tipos que lidam com meu caso, mas não lidam com o caso em que ele tem que adivinhar quais são os OwnProps (por exemplo connect()(DumbComponent) ). Meu changeset está aqui:
https://github.com/DefinitelyTyped/DefinitelyTyped/compare/master...ritwik:react-redux/fix-ownprop-inference
Gostaria de ajudar a resolver isso, mas estou atingindo os limites do meu conhecimento com texto datilografado. Se alguém tiver pensamentos sobre o meu caso de teste ou sugestões, adoraria discutir isso.

Apenas fechando o loop aqui - https://github.com/DefinitelyTyped/DefinitelyTyped/pull/17196 parece que corrige isso para nossa base de código.

Isso foi resolvido? Atualmente estou recebendo esse problema em ^5.0.8 ( IntrinsicAttributes & IntrinsicClassAttributes<Component<Pick ... ). A única diferença é que estou usando types em vez de interfaces .

qualquer um? este é um verdadeiro showtopper para mim, infelizmente ...

@proProbe Você poderia fornecer suas versões @types/react-redux , @types/react e redux e uma amostra que reproduza o erro?
Também autores do pacote CC: @tkqubo @thasner @kenzierocks @clayne11 @tansongyang @nicholasboll

Desculpe pela resposta tardia! Eu estava trabalhando com uma amostra para reproduzi-lo. De repente, percebi que isso foi corrigido em @types/react-redux: "^5.0.8". Obrigado embora!

Ainda recebendo com "^5.0.10" :(

"@types/react": "^15.6.4",
"redux": "3.7.2",
"@types/react-redux": "^5.0.10"

Posso compartilhar um trecho de código com um autor de pacote, mas infelizmente não publicamente.

O downgrade para 4.4.40 como sugerido acima removeu imediatamente o erro.

Consegui resolver isso em minha própria base de código parametrizando o tipo connect no tipo do valor de retorno de mapStateToProps e o que eu queria que ownProps fosse. Retirado do contexto se eu quiser chamar minha lista de produtos com uma lista de IDs de produtos como:

<ProductList productIDs={productIDs} />

e tenha mapStateToProps para traduzir esses id's em produtos a serem mostrados na lista como:

const mapStateToProps = (state: RootState, ownProps: {productIDs: List<UUID>}) => {
  return { products: state.get('products').filter(
    (p: Product) => ownProps.productIDs.contains(p.uuid)) };
};

então eu tive que parametrizar connect como:

const ProductList = connect<ProductListProps, void, {productIDs: List<UUID>}>(mapStateToProps)(ProductListComponent);

Após alguma investigação. Encontrei uma solução simples. O que você só precisa fazer é ter "compilerOptions": { "strict": true } em seu tsconfig.json se estiver conectando um componente React.Component<,>.

Typescript 2.8.x corrige isso. Atualize e experimente.

Quebra novamente no Typescript 3.0.1. Olá Thiene!

Rompendo com o TypeScript 3.2.2 também.

Esse problema tem alguma atualização?

Quebrou para mim com o Typescript 3.2.2 também. No entanto, anotar connect com connect<Props> parece corrigi-lo.

Eu tenho o mesmo problema, mesmo com anotando connect :/

Também estou com o mesmo problema, nenhuma atualização?

Rompendo com o TypeScript 3.2.4 também.

Parece que isso não será resolvido em breve.

Para todos com esse problema, certifique-se de importar o componente conectado corretamente. Mudei um componente já existente para ter uma função connect() uma vez que precisava acessar o estado do aplicativo do redux. Ao fazer isso, mudei de exportar uma função sem estado para exportar meu componente de classe como padrão. Quando não alterei como estava importando em outros arquivos, esse erro apareceu.

Está funcionando.

Existe alguma solução alternativa para pelo menos silenciar esse erro localmente?

Definitivamente parece que há um flip flop em algum lugar no OwnProps versus StateProps. Estou vendo esse problema em que temos um componente conectado ao Redux que possui filhos.

Tudo o que fiz para silenciar esse problema foi usar <any> :

export default connect<any>(states, actions)(SomeComponent);

também funciona se você usar compose:

export default compose<any>(
  connect(states, actions),
  withStyles(styles)
)(SomeFunctionalComponent);

Isso deve silenciar o erro ao passar props para o componente 'inteligente'/conectado.

EDIT: Acabei de reler o tópico novamente e parece que a solução alternativa do @themodernlife é a melhor solução alternativa (ou seja, anotar conectar ou compor usando a interface ou tipo Props):

Isso também não destrói toda a verificação de tipos e o Intellisense? Então, qual é o ponto de adicionar as tipagens então? @dcefram

Sim, é uma solução alternativa apenas para silenciar o compilador e permitir que ele seja construído para evitar que isso seja um "interruptor de exibição" (ou no meu caso, para impedir que eu reescrever tudo longe do TS ou ficar parado até que uma correção seja lançada ). Não é a solução embora.

Eu também, estou esperando a correção para isso :)

A melhor solução é digitar manualmente a chamada connect assim:

type StateProps = {
  // Attributes that you want mapped from redux store
}
type DispatchProps = {
  // Dispatch actions
}
type OwnProps = {
  // Other props that component expects when being created
}
type Props = StateProps & DispatchProps & OwnProps;
class ExampleComponent extends React.Component<Props> { /* ... */ }

const mapStateToProps = (state: State, ownProps: OwnProps): StateProps => { /* .. */ }
const mapDispatchToProps = (dispatch: Dispatch): DispatchProps => { /* ... */ }

export default connect<StateProps, DispatchProps, OwnProps>
  (mapStateToProps, mapDispatchToProps)(ExampleComponent)

Isso deve criar o componente conectado correto que espera OwnProps ao ser criado e nenhum outro estado ou props de despacho.

Negativo. Ele ainda está tentando inferir os tipos. Em vez disso, tenho que substituir manualmente, digite const e depois retorne-o como padrão.

const connected: React.ComponentType<OwnProps> = connect<StateProps, DispatchProps, OwnProps>(......)(Component);
export default connected;

Enfrentando o mesmo problema com connect() usando "@types/react-redux": "7.0.1" e "typescript": "3.4.5" . Nenhuma solução mencionada parece ter ajudado. @TroySchmidt Você pode compartilhar como você usou esse "conectado" no componente pai, se possível, algum código de exemplo seria muito útil

Olá, tive um erro semelhante. react-redux não parece resolver o valor de retorno de mapStateToProps como "TInjectedProps", o que causa a exclusão errada no auxiliar Omit @types/react-redux index.d.ts:110 export type InferableComponentEnhancerWithProps .

a definição do tipo na função connect resolve o problema

// connect Redux
export const RCHeader = connect
<IHeaderStateToProps, //returned by mapStateToProps
 {}, // not necessary
 IHeaderProps, // props you want to pass through jsx/tsx
 IHeaderConnectedReduxStateProps, // combined from IHeaderMapStateToProps and IHeaderProps
 {}// not necessary
>(
    (state: ISettingsState ): IHeaderStateToProps => {
        return {
            headerLogoURL: state.settings.headerLogoURL
        }
    },
    undefined,
    undefined,
    { forwardRef: true }
)(Header);
{
  "dependencies": {
    "react": "^16.8.6",
    "react-redux": "^6.0.1",
    "redux": "^4.0.1"
  },
  "devDependencies": {
    "@types/react": "^16.8.17",
    "@types/react-redux": "^7.0.6",
    "react-scripts-ts": "^4.0.8",
    "typescript": "^3.4.5"
  }
}

Existe alguma atualização para isso?

Recentemente, eu escrevi um componente que iria connect para redux. Quando eu uso este componente em outro lugar, todos os adereços dele estão faltando. E corrigi-lo por:

type StateProps = {
  /* some code */
};

type DispatchProps = {
  /* some code */
};

type OwnProps = {
  /* some code */
};

type Props = StateProps & DispatchProps & OwnProps;

const mapStateToProps = (state: IReduxState): StateProps => ({
  /* some code */
});

const mapDispatchToProps = (dispath: Dispatch<AnyAction>): DispatchProps => {
  /* some code */
};

const BaseComponent: React.FC<Props> = (props: Props) => {
  /* some code */
};

export const ConnectedComponent: React.ComponentType<OwnProps> = connect<
  StateProps,
  DispatchProps,
  OwnProps,
  IReduxState
>(
  mapStateToProps,
  mapDispatchToProps
)(BaseComponent);

dependências estão abaixo:

{
  "dependencies": {
    "react": "^16.8.6",
    "react-dom": "^16.8.6",
    "react-redux": "^7.1.0",
    "redux": "^4.0.1",
  },
  "devDependencies": {
    "@types/react": "^16.8.22",
    "@types/react-dom": "^16.8.4",
    "@types/react-redux": "^7.1.0",
    "@types/redux": "^3.6.0",
    "typescript": "^3.5.2"
  }
}

adicionar todos esses tipos em vez de ter alguma inferência básica de tipos não me parece uma boa solução ...

Isso ainda parece um problema. Bastante certo que o problema foi introduzido na versão 7.0.2 , pois posso instalar 7.0.1 e a inferência de tipos funciona corretamente.

Funciona para mim.
@justemit postou a abordagem correta que funciona nas últimas versões do react e redux.

@justemit Obrigado, isso me deixou louco 🙌

Edit: consertei o problema usando React.FC<Props> 😅

Eu acho que esse problema ainda está vivo e bem em @types/react-redux@^7.1.2 :

const propTypes = {
  foo: PropTypes.number.isRequired,
  bar: PropTypes.func.isRequired
};

// inferring the Props type
interface Props extends PropTypes.InferProps<typeof propTypes> {}
// although doing it explicitly also yields the same result
interface Props {
  foo: number,
  bar: (...args: any[]) => any
}

const Foo = (props : Props) => <></> // EDIT: incorrect way to define functional components
const Foo : React.FC<Props> = (props) => <></> // EDIT: the correct way
//          ^^^^^^^^

Foo.propTypes = propTypes;
/* Foo.defaultProps = {
  foo: 1,
  bar: () => {}
} //*/

const mapStateToProps = (state : any) => ({
  foo: 1
})
const mapDispatchToProps = {
  bar: () => {}
}
const Bar = connect(mapStateToProps, mapDispatchToProps)(Foo)

const Baz = () => <Bar /> // throws an error
Type '{}' is missing the following properties from type 'Readonly<Pick<Pick<Props, never>, never> & Pick<InferProps<{ foo: Validator<number>; bar: Validator<(...args: any[]) => any>; }>, "foo" | "bar">>': foo, bar



md5-e744aa0bac3ac7f45f015259c5597ea9



O tipo 'ConnectedComponentClass<...>' não pode ser atribuído ao tipo 'ComponentType<{}>'.
O tipo 'Readonly<{}>' não possui as seguintes propriedades do tipo 'Readonly; bar: Validator<(...args: any[]) => any>; }>>': foo, barra

And even if typing everything explicitly helped, I agree with <strong i="16">@alexandrudanpop</strong> that it should be possible to infer those types instead of doing everything manually 🤔 

**Edit:** for anyone looking for inspiration for a workaround, I currently resort to explicitly casting using `unknown`:
```ts
// assumes `mapDispatchToProps` is an object, could be a function if used with `ReturnType`
type OwnProps = Omit<Props, keyof ReturnType<typeof mapStateToProps> | keyof mapDispatchToProps>
connect(mapStateToProps, mapDispatchToProps)(Foo) as unknown as React.ComponentType<OwnProps>

Algo que pode ajudar na inferência (ainda com algum trabalho manual) está fazendo algo assim
Saindo do exemplo @kdmadej

type StateProps = ReturnType<typeof mapStateToProps>;
type DispatchProps = typeof mapDispatchToProps;
type OwnProps = {
  a: string;
  b: number;
}

type Props = StateProps & DispatchProps & OwnProps;

const Foo = (props : Props) => <></>

const mapStateToProps = (state : any) => ({
  foo: 1
})

const mapDispatchToProps = {
  bar: () => {}
}

export default connect(mapStateToProps, mapDispatchToProps)(Foo)


// In another file
const Baz = () => <Bar /> <-- this should throw error expecting `a` and `b`

O problema que estou enfrentando, no entanto, é quando adiciono OwnProps à mistura. Usar <Bar /> em qualquer lugar deve gerar um erro por causa da falta de adereços a e b , mas não é, e está realmente me incomodando (sem trocadilhos).

Eu contornei isso usando isso

const ConnectedBar: React.ComponentType<OwnProps> = connect(mapStateToProps, mapDispatchToProps)(Bar);
export default ConnectedBar;

ou equivalente

export default connect(mapStateToProps, mapDispatchToProps)(Foo) as React.ComponentType<OwnProps>;

Corrigi meus problemas usando React.FC<Props> para digitar corretamente o componente de função 😉
Atualizado o post original

Alguma atualização sobre isso? Como o @alexandrudanpop disse, adicionar todos esses tipos em vez de ter alguma inferência básica de tipos não parece uma boa solução. Estou usando 7.2.1 e ainda tenho o mesmo problema.

Nos meus outros componentes eu tenho:

const connector = connect(mapStateToProps, mapDispatchToProps);
type PropsFromRedux = ConnectedProps<typeof connector>;
type Props = PropsFromRedux & OwnProps;

mas isso não parece funcionar se o pai também estiver enviando alguns adereços.

Também passando pelo mesmo problema.
Começou a quebrar após a atualização do npm.
Minha correção é a seguinte:
export default connect(mapStateToProps)(ConnectedIntlProvider) as unknown as ComponentType<unknown>;
Como desconhecido porque não há OwnProps. Só deve ir OwnProps.

No entanto, desta forma funciona:
export default connect<StateFromProps, null, OwnProps, ApplicationState>(mapStateToProps)(viewWithIntl);

Mas desta forma não:
export default connect<StateFromProps, DispatchFromProps, OwnProps, ApplicationState>( mapStateToProps, mapDispatchToProps, )(attachmentFormWithIntel)
E requer o sufixo:
as unknown as ComponentType<OwnProps>;

Usando
"@types/react": "16.9.49",
"@types/react-redux": "^7.1.9",
"datilografado": "^4.0.3"
"redux": "^4.0.5",
{
"dependências": {
"reagir": "^16.13.1",
"react-dom": "^16.13.1",
"react-redux": "^7.2.1",
"redux": "^4.0.5",
},
"devDependencies": {
"@types/react": "16.9.49"
"@types/react-dom": "16.9.8",
"@types/react-redux": "^7.1.9",
"datilografado": "^4.0.3"
}
}

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

tyv picture tyv  ·  3Comentários

fasatrix picture fasatrix  ·  3Comentários

csharpner picture csharpner  ·  3Comentários

jrmcdona picture jrmcdona  ·  3Comentários

jbreckmckye picture jbreckmckye  ·  3Comentários