Definitelytyped: React.d.ts ReadOnly<t>em estado e adereços</t>

Criado em 25 jan. 2017  ·  91Comentários  ·  Fonte: DefinitelyTyped/DefinitelyTyped

Olá @ericanderson

Estou tendo muitos problemas com essa mudança quando usada na prática:

Problema 1: Ir para definição

Quando você pressiona Go To Definition em uma propriedade de props ou state, o Typescript não consegue resolvê-lo.

interface MyComponentProps {
    name: string;
}

export abstract class MyComponent extends React.Component<MyComponentProps , void> {
    myMethood() {
       this.props.name; //<-- Go To definition in name
   }
}

image

Faz sentido porque o membro é gerado sinteticamente, mas é irritante de qualquer maneira.

Problema 2: Hierarquias de componentes (P genérico com restrições)

Mais importante, se você criar um componente abstrato assim:

interface MyBaseProps {
    onChange?: (val: any) => void;
}

export abstract class MyBase<P extends MyBaseProps> extends React.Component<P, void> {
    myMethood() {
        this.props.onChange!(2); //The type is S["onChange"] instead of (val: any) => void and so is not invocable. 
   }
}

TS é capaz de mostrar que existe uma propriedade onChange, mas às vezes não consegue descobrir seu tipo.

image

Esta é a mudança mais importante, pois me impede de ter hierarquias de componentes que compartilham props e funcionalidades comuns. Parece um problema no compilador TS, mas até que seja corrigido.

Problema 3: Não tão somente leitura.

Embora eu concorde que essa mudança captura bem a intenção funcional do React, existem situações válidas em que você pode modificar o estado imperativamente, como no construtor, e também se você alterar o estado e chamar forceUpdate tudo funciona bem.

C# this.state.name = "John"; this.forceUpdate(); //Ok as long as you don't setState afterwards, but calling setState also is annoying with the callback.

É recomendado? Não.
É proibido? Também não, caso contrário forceUpdate não existirá.

Claro que você pode converter o estado para S (ou any ) e fazer a alteração, mas se for um padrão comum fica complicado.

Conclusão: vale a pena?

Fico triste que o novo recurso brilhante do TS crie mais problemas do que soluções neste caso, mas honestamente acho que esse é o caso aqui.

Por outro lado, a mudança de setState é ótima 👍 , não sabia de Pick<S,K> .

Comentários muito úteis

O problema 3 está em debate, eu acho.

Você está certo de que pode _tecnicamente_ fazer o exemplo acima no React, mas eu definitivamente argumentaria que não é assim que o React deveria ser usado.

Isso pode ser dividido em 3 casos distintos.

Inicialização genérica

interface State {
  bar: number;
}

interface Props {
  baz: number;
}

class Foo extends React.Component<Props, State> {
  public state: State = {
    bar: 5,
  };
}

Inicialização baseada em adereços

interface State {
  bar: number;
}

interface Props {
  baz: number;
}

class Foo extends React.Component<Props, State> {
  constructor(props: Props) {
    super(props);
    this.state = {
      bar: props.baz,
    };

    // or
    this.setState({
      bar: props.baz,
    });
  }
}

Atribuição aleatória com forceUpdate

Dado que acho que é melhor empurrar as pessoas para a coisa "certa", você pode contornar facilmente esse problema redeclarando public state :

interface State {
  bar: number;
}

class Foo extends React.Component<{}, State> {
  public state: State;
  public myMethod() {
    this.state.bar = 5;
  }
}

Todos 91 comentários

Qual versão do typescript seu visual studio está usando?

@vsaio para sa

Para o problema 1, com o TS 2.1.5 e o VSCode mais recente, isso funciona bem para mim. Eu não tenho windows/VS, então não posso verificar lá, mas aposto que há atualizações para seus plugins ou você não está no TS 2.1.5

O mesmo para o problema 2

VS 2015 com TS 2.1.5.0

O problema 3 está em debate, eu acho.

Você está certo de que pode _tecnicamente_ fazer o exemplo acima no React, mas eu definitivamente argumentaria que não é assim que o React deveria ser usado.

Isso pode ser dividido em 3 casos distintos.

Inicialização genérica

interface State {
  bar: number;
}

interface Props {
  baz: number;
}

class Foo extends React.Component<Props, State> {
  public state: State = {
    bar: 5,
  };
}

Inicialização baseada em adereços

interface State {
  bar: number;
}

interface Props {
  baz: number;
}

class Foo extends React.Component<Props, State> {
  constructor(props: Props) {
    super(props);
    this.state = {
      bar: props.baz,
    };

    // or
    this.setState({
      bar: props.baz,
    });
  }
}

Atribuição aleatória com forceUpdate

Dado que acho que é melhor empurrar as pessoas para a coisa "certa", você pode contornar facilmente esse problema redeclarando public state :

interface State {
  bar: number;
}

class Foo extends React.Component<{}, State> {
  public state: State;
  public myMethod() {
    this.state.bar = 5;
  }
}

Meus problemas são com a variação de genéricos. especificamente para digitar dentro da classe que é tipada genericamente. abaixo está uma amostra bem mínima de onde as coisas quebram.

class TBaseState {
  public value: string;
}

function globalFunc<T extends Readonly<TBaseState>>(item: T) {
}

class MyComponent<TProps, TState extends TBaseState> extends React.Component<TProps, TState> {
  broken() {
    // typing of this.state is Readonly<TState>
    // this is not assignable to Readonly<TBase>
    globalFunc(this.state);

    // this is a horrible hack to fix the generics variance issue
    globalFunc(this.state as TState as Readonly<TBaseState>);
  }
}

class MyState extends TBaseState {
}

let component: MyComponent<any, MyState>;

// here the typing of component.state is Readonly<MyState>
// this is assignable to Readonly<TBase>
globalFunc(component.state);

Estou no TS 2.1.5.0

image

mas pode ser que no VS tenhamos uma experiência de TS pior do que no código VS ...

para o Problema 1, vá para a definição TS também não funciona no VS Code:

interface MyComponentProps {
    name: string;
}

export abstract class MyComponent extends React.Component<MyComponentProps , void> {
    fullName: string;
    myMethood() {
       this.props.name; //<-- doesnt work
       this.fullName; //<-- works
   }
}

para o Problema 2, é verdade que o VS Code se comporta melhor:

image

enquanto VS parece confuso:

image

Eu acho que para o VSCode e o problema 1, está funcionando porque estou usando o plugin para o "Latest Typescript and Javascript Grammar" que deve ter um manuseio mais inteligente.

@patsissons é um exemplo interessante, embora eu ache que seja mais representativo de um bug no texto datilografado do que um bug no arquivo de definição. Por exemplo, setState costumava levar S que significava fazer parciais que costumávamos fazer truques estranhos como setState({foo:5} as any as State) ou usar aquele que recebe uma função. Não tenho certeza se a falta de expressividade do compilador torna as tipagens "erradas". Eu acho que este é um argumento decente para uma mudança no README para marcar este caso extremo.

Você registrou um problema no TS?

Portanto, essa mudança hoje em dia quebra todos os VS e desativa Go To Definition em todos os VS Codes, exceto se você tiver um plug-in ...

Também há o argumento da completude. Existem zilhões de APIs que deveriam ser Readonly e não são hoje em dia, apenas em React.d.ts

 interface ComponentLifecycle<P, S> {
        componentWillMount?(): void;
        componentDidMount?(): void;
        componentWillReceiveProps?(nextProps: Readonly<P>, nextContext: any): void;
        shouldComponentUpdate?(nextProps: Readonly<P>, nextState: Readonly<S>, nextContext: Readonly<any>): boolean;
        componentWillUpdate?(nextProps: Readonly<P>, nextState: Readonly<S>, nextContext: Readonly<any>): void;
        componentDidUpdate?(prevProps: Readonly<P>, prevState: Readonly<S>, prevContext: Readonly<any>): void;
        componentWillUnmount?(): void;
    }

Eu acho que readonly deve ser usado para 'freeze' ou 'Inmmutable.js' não para a cauda longa de pensamentos que não devem ser modificados, como objetos de evento, por exemplo.

Não arquivei, estou apenas adaptando meu código hoje para lidar com os novos tipos Readonly<T> , este foi um caso que encontrei para o qual não tinha uma solução digitada corretamente. Vá em frente e registre um problema, estarei ocupado a maior parte do dia de hoje com o código de correção.

Ah sim, eu sabia que tinha perdido alguns. @olmobrutall Se mantivermos as alterações de estado que introduzi para marcar como somente leitura, concordo que esses métodos devem ser atualizados. Eu sinto que precisamos de um consenso sobre a coisa certa a fazer primeiro.

Quanto às quebras de VS, não sei o que está certo. Os tipos devem ser retidos porque algumas ferramentas não estão atualizadas?

@patsissons Você sempre pode fornecer suas próprias tipagens para reagir por enquanto se quiser esperar para ver como isso se desenrola antes de atualizar todo o seu código. https://ericlanderson.com/using-custom-typescript-definitions-with-ts-2-x-3121db84015d#.ftlkojwnb

em nossa experiência, o VS está sempre um pouco atrasado. Nossa loja usa o vscode para fazer qualquer desenvolvimento ativo datilografado e o VS é usado mais para simplesmente corrigir arquivos de código ou para desenvolvedores não digitados examinarem o código, não necessariamente para desenvolvimento ativo.

@ericanderson o hack não é tão ruim por enquanto, eu só tenho que peneirar Readonly<T> para pegar meu T que é atribuível ao Readonly<Base> .

Estamos falando de 'react.d.ts', essa declaração de membro único é usada massivamente. Acho que vale a pena esperar até que o VS esteja pronto.

Além disso, como 50% dos tipos no mundo devem ser somente leitura, como objetos que você obtém de APIs, não acho que precisamos anotar isso.

Eu acho que Readonly deve ser usado para objetos que foram explicitamente convertidos para ter propriedades somente get. Como congelar.

@olmobrutall Readonly é novo, então a prática recomendada exata não está realmente definida. Eu pessoalmente preferiria que tudo declarasse que é preciso um Readonly<> de coisas para ajudar a significar que não vai mudá-lo. Da mesma forma, o React não espera que você modifique state fora de setState e, portanto, essa alteração garante que acidentes não introduzam bugs, que é um dos principais benefícios de usar TypeScript em vez de javascript.

Se o desempenho fosse mais consistente nos navegadores para Object.freeze , imagino que o pessoal do React realmente começaria a congelar depois setState .

Qual é o propósito do forceUpdate então?

Estou curioso sobre os pensamentos de outras pessoas sobre como o FixedTyped deve funcionar em relação às atualizações de ferramentas, bem como a filosofia sobre Readonly em reagir (e outras bibliotecas cuja intenção é que você não modifique determinados objetos).

cc/ @johnnyreilly @vsaio @pspeter3 para pensamentos sobre reagir especificamente e outros pensamentos em geral
cc/ @andy-ms @mhegazy para pensamentos sobre como o FixedTyped deve proceder filosoficamente para atualizações de ferramentas e uso zeloso de Readonly

@olmobrutall usamos forceUpdate para enfileirar uma renderização no lado de reação, acionado por eventos observáveis ​​no lado do estado.

ATUALIZAÇÃO :
Vou esclarecer um pouco nosso cenário para que não seja mal interpretado. Nossos objetos de estado são objetos imutáveis ​​de longa duração (então Readonly<T> é realmente muito adequado para nós). Esses objetos de estado contêm vários fluxos observáveis rxjs que afunilam em um observável de notificação chamado stateChanged . Os componentes do React observam este observável para eventos e afunilam esses eventos em uma chamada para forceUpdate (após o debounce). Com efeito, nosso estado mutável vive dentro do estado, mas o próprio estado e os membros que existem no estado são todos imutáveis. Este certamente não é o caso de uso padrão para React, mas é muito semelhante em fluxo. Simplesmente temos objetos de estado inteligente que sabem informar os componentes quando uma nova renderização é necessária.

@ericanderson o principal problema é que essas definições de tipo estão sofrendo com problemas de SemVer. Como as versões de definição de tipo estão amplamente vinculadas às suas respectivas versões de módulo, acabamos com um pequeno aumento de versão que traz alterações na definição de tipo, o que significa que temos que fixar as versões @types em nosso package.json Arquivo.

@olmobrutall Dos documentos do react:

Normalmente você deve tentar evitar todos os usos de forceUpdate() e apenas ler this.props e this.state em render().

O guia de reação na verdade diz para você não atualizar o estado diretamente: https://facebook.github.io/react/docs/state-and-lifecycle.html#do -not-modify-state-directly

forceUpdate , como eu li, é apenas para forçar seu componente a atualizar quando seu componente é baseado em dados _não_ em suas props ou seu estado.

@patsissons Posso estar errado, mas acredito que SemVer foi projetado para ser compatível com APIs e intenções semânticas. Só porque você usa uma biblioteca de uma maneira não pretendida (de acordo com os documentos) não significa que a biblioteca deve continuar suportando esses usos não intencionais. Os autores da biblioteca estão bem dentro do SemVer para alterar a semântica que estava incorreta, mas passou a ser usada por algumas pessoas.

Dito isso, talvez Readonly<> para state seja uma mudança muito grande, mas suponha por um momento que seja a mudança certa. Quando deve ser lançado no Definitivamente Typed? Seu código sempre sofrerá a necessidade de mudar assim que você receber a atualização que finalmente marca state como Readonly<> .

Eu ainda não sei o que é certo sobre Readonly<> ser aplicado a state que torna difícil debater semver, ou ferramentas, ou qualquer outra coisa. Meu instinto era que estava certo. As pessoas que revisaram a mudança nunca a abordaram como um problema. Parece alinhado com a intenção da equipe React.

Fico feliz em adiar a qualquer um dos revisores para reagir em Definitivamente Typed (eu cc'd todos eles acima).

Então o Observable muda o estado e você forceUpdate? Portanto, mudar o estado de forma imperativa é de alguma forma permitido.

Eu entendo que onde Readonly deve ser usado não está 100% definido. Mas precisamos começar com uma propriedade controversa e massivamente usada antes que as ferramentas estejam prontas?

Sou a favor de fortemente tipados, mantenho 6 projetos todos com strictNullChecks, mas os benefícios aqui são bem menores do que os problemas que produz atualmente.

@ericanderson Acredito que SemVer2 foi projetado para permitir declarações de versão de nó como ^15.0.0 e espero que quaisquer atualizações menores ou de patch (ou seja, 15.0.1 ou 15.1.0 ) para o módulo sejam transparentes ou pelo menos retrocompatível de uma perspectiva externa. Quaisquer atualizações importantes ( 16.0.0 ) exigiriam um ajuste na declaração de versão para trazer a mudança. Isso basicamente impede que mudanças de ruptura sejam trazidas para o sistema de digitação. Mas, atualmente, as versões de definição de tipo não podem se desviar de suas respectivas versões de módulo, versão principal (por convenção), o que resulta nessa descontinuidade.

A versão curta é que as definições de tipo podem ter alterações importantes introduzidas sem que o próprio módulo seja alterado, e as alterações importantes exigem um aumento de versão principal.

Mas você não vai fazer uma PR removendo forceUpdate, não é?

Então, se forceUpdate estiver lá, alterar o estado de forma imperativa também deve estar lá.

Em teoria, você deve usar um gráfico de estado imutável profundo, mas muitas vezes alterar o estado imperativamente é bom e nem todos os desenvolvedores compram a ideia de estruturas de dados persistentes.

Felizmente, o React permite uma rota de escape e possibilita mudanças diretas no estado, vamos proibir os desenvolvedores de TS de seguir esse caminho? Não é muito paternalista?

O Vue.js, por exemplo, promove as mudanças imperativas, não ficarei surpreso se influenciar o React.

Também estava lendo um post no blog de algum autor do React não muito tempo atrás (eu me lembro) incentivando o uso do React sem toda a cerimônia do Redux.

Minha posição, caso contrário, é obter as definições de tipos publicadas o mais rápido possível, minha única preocupação é a automação. uma vez que, dado o estado atual do versionamento de definição de tipo, uma compilação sucessiva sem alterações de origem pode ser interrompida. Esses tipos de falhas de IC não determinísticas são preocupantes. Ninguém quer ver sua construção quebrar porque eles empurraram uma mudança e depois descobrem que sua mão de mudança não tem nada a ver com a quebra de construção.

Depois de dormir nele, minhas opiniões pessoais são as seguintes:

  • A boa prática envolveria o uso de fios ou bloqueios npm, para que você não tenha uma surpresa, a menos que tenha atualizado localmente primeiro.
  • Tornar o estado somente leitura é como o React deve ser usado. A documentação e os exemplos confirmam isso.
  • O fluxo de trabalho em que você não deseja usar setState está dentro de sua base de código e dentro de seus próprios direitos. Você está certo de que o React fornece forceUpdate, mas seu uso destina-se a causar uma renderização quando você está fora do caso de uso pretendido. Portanto, se você não quiser usar state como pretendido, tudo bem, mas nesse ponto você não precisa usar a variável de instância state. Na verdade, você pode usar apenas variáveis ​​privadas regulares.
  • Sim, este projeto depende de muitas pessoas e, no entanto, até agora, essas são as duas únicas reclamações até agora que me fazem pensar que esse não é um problema generalizado. Além disso, o problema levantado sobre a função global pode ser reescrito para usar o genérico de maneira diferente (consulte o problema vinculado do TypeScript)

Considerando os pensamentos acima, bem como as soluções alternativas para aplicativos React não padrão, acho que Readonly está correto e a única alteração necessária para a integridade é atualizar os métodos do ciclo de vida para corresponder.

Concordo que essas mudanças fazem todo o sentido, meu caso de uso que estava causando problemas era um caso de canto muito exclusivo que raramente deveria ser encontrado. Ao adaptar minha base de código para props e state readonly, peguei alguns problemas de digitação indetectáveis. Não há dúvida de que publicar as alterações foi a escolha correta.

Patsisson, usando VS, VS Code ou qualquer outro editor?

Meu ponto é que, embora o React promova uma abordagem funcional, ele permite um fluxo de trabalho semelhante ao de um videogame, onde você faz alterações no mundo imperativamente (estado) e depois renderiza (forceUpdate). Essa abordagem agora é proibida no TS. Tipo de func-damentalismo :)

Vou pensar em alternativas para tornar meu ecossistema atual viável então...

Problema 2 jogando erro apenas com strictNullChecks .

[TS] Cannot invoke an expression whose type lacks a call signature. Type '((val: any) => void) | undefined' has no compatible call signatures.

+1 estou usando strictNullChecks

@ericanderson ?

Como dito acima, isso está relacionado ao ferramental, que está claramente fora do escopo do DT. Se você estiver no VSCode e instalar a visualização do próximo analisador TS, não vi esse problema com strictNullChecks quando estava escrevendo qualquer um dos itens acima.

Eu não tenho janelas, então não posso falar com o VS propriamente dito.

este patch Pick quebrou as sugestões do VSCode. ao fazer this.setState({ | }) (Ctrl + Espaço), nada é mostrado, mesmo que o Estado esteja claramente definido e usando Partial<State> porque setState pode definir o estado dos membros seletivamente

IMHO o código correto deve ser setState(state: Partial<S>, callback?: () => any): void;

Conforme discutido na ramificação de solicitação pull original, começamos com Partial. No entanto, se o seu objeto de estado for:

estado da interface {
foo: cadeia;
}

Então, com parcial, você pode fazer o seguinte:

setState({foo: undefined});

O que está claramente errado.

Desculpe - mas novamente sobre Readonly

React não é apenas Redux e setState. React também é mobx e outros padrões observáveis, onde a atribuição de propriedades de estado é o PRINCIPAL RECURSO . A mudança discutida elimina totalmente o uso do mobx com texto datilografado.

Então, por que adicionar o comportamento que não existe no código de reação original ao arquivo .d.ts? .d.ts deve ser o reflexo da biblioteca original, mas não o ensinamento das pessoas ao estilo de codificação correto, de acordo com o ponto de vista do autor!

@lezious , receio não entender sua posição. Você pode fornecer um exemplo de código e o que há de errado nas tipagens em relação ao exemplo? Obrigado!

Sem problemas:

esta é minha classe estadual

class UserInfoBlockState  
{
    <strong i="7">@observable</strong>                  <- this is mobx way to declare state
    public updating: boolean;
    <strong i="8">@observable</strong> 
    public deleted: boolean;
}

e este é o meu componente

<strong i="12">@observer</strong>       <-- this is mobx way to make component react to state change
export class UserPanel extends React.Component<IUserInfoBlockProps, UserInfoBlockState>
{
   ......
     private updateUser()
    {
        this.state.updating = true;
        UsersAPI.update(this.props.user)
       .then(() =>
            {
                this.state.updating = false;      <--- this is the mobx way to work with the state
            }
        ).catch(() =>
            {
                this.showErrror("Server error");
                this.state.updating = false;
            });
    }
   ....

}

e agora nós (nossa empresa com um projeto enorme escrito em react+mobx) atualizamos o DT e o React no início do novo círculo de lançamento e ... mais de 3000 erros de compilação "propriedade é somente leitura". Uau. O que você sugere que eu faça - reescrever todo o projeto para redux, nunca atualizar react.d.ts ou sempre manter e suportar a versão bifurcada?

@mweststrate , por favor, verifique isso.

@Iezious Agradeço sua posição e peço que se acalme. Estou tentando trabalhar com você. Isso não tem nada a ver com Redux, mas puro React.

Não quero que o DT bloqueie um caso de uso que funcionou anteriormente, no entanto, não acho que você descreve o uso de mobx com react seja consistente com a documentação do react (nem mesmo a documentação do mobx agora que li sobre isto).

O React afirma claramente na documentação que existem 3 maneiras de usar o estado corretamente, e a primeira é "Não modifique o estado diretamente".

Isso me leva a acreditar que a maneira como sua base de código funciona atualmente provavelmente quebrará em futuras versões do react. Ao examinar https://github.com/mobxjs/mobx-react , não vejo nenhuma sugestão de que você use o estado dessa maneira. Na verdade, parece que eles querem que você use propriedades.

Revendo https://mobx.js.org/getting-started.html e pesquisando por "mobx react state", não consigo encontrar qualquer documentação que sugira que você use o mobx da maneira que está fazendo.

A DT deve transmitir o espírito da biblioteca subjacente na melhor das hipóteses e a implementação real na pior das hipóteses e é claro que comprar o componente reagir e estender significa respeitar o contrato implícito.

Não tenho certeza do que sugiro que você faça. Algumas opções que eu posso pensar de improviso:

  1. Uma opção "barata", se você insistir em assumir a variável state é pesquisar e substituir React.Component por MyComponent e definir MyComponent como uma subclasse de React.Component sem as restrições readonly.
  2. Outra, com base nos exemplos idiomáticos postados na documentação do mobx, é parar de usar this.state e apenas usar variáveis ​​no React.Component real. Isso pode ser um pouco doloroso, mas pelo menos novas pessoas em seu projeto poderão ver os padrões em sua base de código conforme eles são descritos online.
  3. Você pode redeclarar state em cada componente se quiser continuar fazendo da mesma forma que está fazendo.
  4. Você pode pesquisar e substituir this.state por this.somethingElse e declarar manualmente.
  5. Você pode parar de receber atualizações para reagir do DT (e possivelmente no futuro de reagir em geral, dependendo de como as alterações futuras podem afetar seu caso de uso).

Se fosse meu projeto, provavelmente faria o número 2, embora não saiba o suficiente sobre mobx para ter certeza.

Desculpe, eu não pude concordar com você (não significa que os outros não vão concordar com você). Tentei encontrar uma razão para reverter essa parte, mas não consigo embarcar neste momento.

Vou mencionar novamente nossa estratégia, que é uma aplicação personalizada de observáveis ​​RxJs para conduzir mudanças de estado React e renderização que se assemelha ao padrão mobx. Usamos ações para receber entrada da camada de visualização (React). Ações são sinônimos de uma função que consome entrada e produz um observável, o que então impulsionaria outros observáveis ​​de estado. Esse padrão permite que o estado permaneça imutável da perspectiva da camada React, pois você só consulta valores observáveis ​​e executa ações de estado. Internamente, seu estado pode se "mutar" como resultado das ações, pois o estado interno não tem restrições somente leitura.

Eu não consigo me acalmar. Tenho o projeto em produção e preciso gastar muito tempo das equipes, e isso significa dinheiro desde essa mudança.

E qual é o motivo? Essa mudança reflete a realidade em reagir? Não. Ele adiciona as restrições e comportamentos que não existem no react, a restrição que é adicionada de alguma forma só porque ele acha que isso está certo.

Qual é o objetivo do projeto DT? Para descrever as bibliotecas JS tão precisas quanto possível, ou descrever nossa visão de como usar corretamente essas bibliotecas? De acordo com o nome "Definitely Typed" é o primeiro. Portanto, se essa restrição não existir na biblioteca JS original, ela NÃO DEVE existir no DT também. Este é o meu ponto. Onde estou errado neste ponto?

Eu entendo que você está frustrado, no entanto, esta é a maneira que o react deveria ser usado lendo os documentos. Dificilmente vejo como devemos tornar o DT menos específico porque sua equipe abusou da biblioteca e violou o contrato implícito.

Mostre-me uma onça de documentação publicada pela equipe do react que sugere que o estado deve ser diretamente mutável e eu imediatamente mudarei o código de volta.

https://facebook.github.io/react/docs/react-component.html#state

Nunca mude this.state diretamente, pois chamar setState() posteriormente pode substituir a mutação que você fez. Trate this.state como se fosse imutável.

Parece bem claro que o react considera this.state imutável. O React não considera as _properties_ de this.state imutáveis ​​(que é a suposição redux). Você é livre para fazer:

this.state.user.name = "foo";

em reação idiomática.

Minha preferência é digitar a API com precisão (o que neste caso significa Readonly ) e expressar todas as invariantes que a equipe de reação declara.

@ericanderson desculpe, acabei de notar isso. FWIW Eu acho que a mudança é razoável e que as ferramentas vão se atualizar. A propósito, você já ouviu falar que eles estão considerando depreciar a sobrecarga de setState que recebe um objeto? O futuro é o estilo de redução setState por todas as contas.

@amoreland Discordo. Por: https://facebook.github.io/react/docs/state-and-lifecycle.html#do -not-modify-state-directly

Não modifique o estado diretamente

Por exemplo, isso não renderizará novamente um componente:

// Wrong
this.state.comment = 'Hello';

Em vez disso, use setState():

// Correct
this.setState({comment: 'Hello'});

O único lugar onde você pode atribuir this.state é o construtor.

@johnnyreilly eu não tinha. Isso é interessante. Fonte?

Isso foi abordado em uma das conversas na recente conferência do React. Está disponível no YouTube. Pode ter sido a palestra de Lin Clark. Uma das primeiras palestras no dia 1 - cobrindo as próximas mudanças para reagir à v16. Fibra etc

Desculpe @gaearon eu quis dizer

A razão pela qual o mobx está realizando mudanças de estado, é porque os observáveis ​​estão direcionando as atualizações do React, em vez de _substituir_ o estado completamente, o estado se torna um mecanismo que impulsiona a renderização. então, fazendo algo como this.state.updating = true; você está realmente fazendo o equivalente a uma substituição de estado, mas em vez disso o estado é inteligente o suficiente para acionar uma nova renderização notificando o componente que o estado foi alterado de seu conteúdo anterior. Concordo que este não é um uso _convencional_ do React, mas sim um uso muito mais abrangente e de nível superior do React. Eu diria que o uso convencional do React é útil apenas para pequenos projetos com um punhado de componentes. Quando você acaba com centenas de componentes, cada um com várias dezenas de drivers de mutação reativa, você não pode mais usar de forma confiável as alterações convencionais de estado do React (ou seja, setState) e deve ser para entreter mudanças arquitetônicas que envolvem o estado _smart_ (que é o que o mobx essencialmente faz ).

Dito isso, eu entendo porque ele está chateado, porque as mudanças de digitação estão afetando um uso mais avançado do sistema React. As atribuições de estado observável não são tecnicamente _mutating_ state, mas sim invocando eventos observáveis ​​para o valor RHS. Acontece que a sintaxe que o mobx escolheu para emitir esses eventos observáveis ​​conflita com a intenção expressa do estado imutável do React.

@Iezious se você precisar de uma solução rápida para esse tipo de problema, você pode se safar aumentando as tipagens React e refatorando seus componentes para usar uma extensão para o tipo React.Component defs.

import * as React from 'react';
declare module 'react' {
  class MutableStateComponent<P, S> extends React.Component<P, S> {
    state: S;
  }
}
(React as any).MutableStateComponent = React.Component;

e agora você pode apenas criar componentes de estado mutáveis ​​como componentes regulares, exceto que seu membro state não está mais marcado como readonly .

export class MyComponent extends React.MutableStateComponent<MyProps, MyState> {
  // this.state.name is writable
}

@patsissons sim, esse é exatamente o motivo.

Não estou alterando o estado, estou usando mobx observables, que chama setState para mim, estou fazendo isso porque meu código de projeto ENORME parece muito mais claro e compreensível.

Eu sei que posso fazer meu componente, também posso fazer no meu servidor npm um script que sempre reverterá essa mudança para nossa empresa. Eu posso usar hack como "this.state.state.updated" e muitos outros hacks.

Eu só quero dizer que essa mudança afeta o uso de padrões observáveis ​​como mobx, que na realidade seguem o caminho de reação, mas agora, já que essa mudança não pode ser compilada e precisa de alguns hacks e soluções alternativas para funcionar. E é por isso que eu acho que essa mudança não está certa.

talvez em vez do meu MutableStateComponent sugerido, nós o chamemos de ObservableComponent que está mais alinhado com o padrão Observable React.

Se você descartar Readonly , as pessoas que estão usando os tipos react com react regular (e/ou qualquer outro sistema de gerenciamento de estado além do mobx) estarão expostas a erros. Eu não uso mobx em meu projeto enorme e aprecio os erros do compilador quando alguém comete um erro de digitação e acidentalmente usa this.state.foo = bar .

Se houver uma troca inevitável entre o uso de reação padrão e o uso de reação não padrão, os tipos de reação padrão devem se inclinar para o primeiro.

Além disso, se você usar mobx da maneira idiomática, isso não é um problema.

Se você descartar Readonly, as pessoas que estão usando os tipos react com react regular (e/ou qualquer outro sistema de gerenciamento de estado além do mobx) estarão expostas a erros. Eu não uso mobx em meu projeto enorme e aprecio os erros do compilador quando alguém comete um erro de digitação e acidentalmente usa this.state.foo = bar.

Então, mais uma vez - você está ENSINANDO A ESCREVER O CÓDIGO

Este projeto não é sobre ensinar a escrever o código, este projeto é para descrever a funcionalidade existente das bibliotecas JS. A limitação discutida não existe na biblioteca original e deve ser excluída.

Isso é tudo.

@patsissons

se você precisar de uma solução rápida para esse tipo de problema, você pode se safar aumentando as tipagens do React e refatorando seus componentes para usar uma extensão para os defs do tipo React.Component.

não está certo. No mundo corporativo, de onde estou, não existem "soluções rápidas". Quando algo muda no SDK ou DEVE ser compatível com versões anteriores, ou leva anos. Não há correções rápidas em mais de 2 milhões de linhas de projeto de código. São semanas de mudanças, testes, testes de produção A/B, lançamentos para um grande número de pessoas. Custa dinheiro real. E todo esse esforço enorme apenas por causa de alguém adicionado mudança não compatível com versões anteriores que NÃO EXISTE NA BIBLIOTECA REAL?

Por que você acha que o forceUpdate ainda existe no react? Eles estão falando em confs sobre o estilo certo, mas fazendo as mudanças para evitar as outras formas de uso. Por quê? Uma vez que é uma grande empresa e eles sabem que as bibliotecas devem ser compatíveis com versões anteriores.

@ericanderson escreveu isso

this.state.state.value = 1 

não é legítimo também do seu ponto de vista. Da próxima vez, ele obterá a ferramenta do TS e adicionará a limitação que impedirá esse código. Ou faça a classe final do componente, ou outra coisa só porque "é o estilo certo e evita que as pessoas cometam os erros".

Prevenir as pessoas de erros - é a tarefa do FB, se eles quiserem fazer isso, eles podem facilmente adicionar proxy e não permitir a mutação de estado. O objetivo do DT é adicionar descrições e nada mais.

@Iezious

Eu acho que o ponto é que a equipe do React não pode tornar o estado imutável com JavaScript, mas se eles pudessem, eles teriam. O TypeScript, por outro lado, pode tornar o estado imutável, e é por isso que essa alteração foi feita nas definições de tipo. Era absolutamente a intenção da equipe do React não permitir modificações nos membros do estado diretamente (como é evidente por seus documentos oficiais sobre o uso correto do estado ), mas eles não tinham as construções de linguagem para impor essa restrição. Essa restrição nunca foi desconhecida, foi bem documentada desde o início. Para aqueles de nós que operam fora do uso _convencional_ do React, devemos pelo menos aderir às recomendações oficiais de uso do React. Para minha equipe, isso significava arquitetar uma solução que nos permitisse conduzir mudanças de estado sem alterar o estado diretamente. Isso foi feito especificamente para garantir que não encontraríamos nenhum problema como este (mesmo que essa mudança tenha nos afetado um pouco, mas apenas por meio de assinaturas de função e não de design fundamental).

Se a refatoração não for possível em sua situação, fixe @types/react em 15.0.1 antes da alteração ser feita, ou simplesmente não use @types/react e mantenha sua própria variante do digite defs e simplesmente altere a digitação state para Component . Eu realmente não acho que você terá sucesso em convencer alguém a reverter a mudança.

forceUpdate existe porque está documentado como o caminho de código recomendado para direcionar a renderização quando o estado estrutural interno é modificado (ou quando render() usa dados fora do estado que são mutáveis). O uso de forceUpdate foi projetado exatamente para o padrão de uso que minha equipe usa com o React.

A equipe do React pode tornar o estado imutável com JS, é fácil. Mas não compatível com versões anteriores.

Mais uma vez, é:

this.state.state.value = 1 

legal ou não?

Acho que sim, mas minha opinião já está clara...

Eu não acho que a conversa sobre mutabilidade / imutabilidade seja relevante _ainda_. Claramente, o bug no compilador TS (em relação Readonly ) combinado com essa mudança torna os componentes genéricos completamente impossíveis de usar, quebrando muitos códigos existentes. Certamente esse é um caso de uso válido universalmente aceito e é motivo suficiente para reverter isso por enquanto??

interface test1 {
    num: number;
}

function add<T extends test1>(initial: T, add: number) {
    var copy: Readonly<T> = initial;

    //ERROR HERE: [ts] Operator '+' cannot be applied to types 'T["num"]' and 'number'.
    return copy.num + add;
}

Alguém sabe se há um problema aberto com a equipe Typescript sobre isso? Não consigo encontrar o problema relevante em seu rastreador.

@caesay Veja Microsoft/TypeScript#15501

eu tenho que init state no construtor, mas tslint mostra "state is readonly"...

constructor(props) {
  super(props);
  this.state = {
     value: props.defaultValue,
  };
}

como posso resolver isso.........

Usar setState

setState não funciona no construtor

Ou considere componentWillMount w/setState

obrigado

Olá,

Eu li todo o tópico, mas não está claro para mim se há planos para lidar com o cenário @alanwei0 ?

Concordo plenamente que faz sentido ter state como ReadOnly . Dito isto, não ser capaz de definir o estado inicial no construtor complica um pouco as coisas porque render é chamado antes componentDidMount ser feito.

@pawelpabich usando this.state = { no construtor não é um problema. Você pode atribuir a variáveis readonly no construtor, e Readonly<T> não impede a atribuição (nunca!).

interface TInterface {
    test: string;
}

class TClass {
    readonly blah: Readonly<TInterface>;
    constructor() {
        this.blah = { test: "constructor" };
    }

    fn = () => {
        this.blah = { test: "fn" };
    }
}

O único erro aqui será dentro fn - não por causa de Readonly<T> , mas por causa da palavra-chave readonly . Na verdade, a versão mais recente das tipagens nem usa a palavra-chave readonly , então você pode atribuir o estado em qualquer lugar, apenas não alterar as propriedades dentro do estado.

O problema sobre o qual estávamos falando aqui era um bug com o compilador typescript que fazia com que as propriedades de estado perdessem seus tipos em componentes herdados. Isso já foi corrigido, acredito, e, nesse caso, esse problema pode ser encerrado.

@caesay desculpe, pensei que era esse o caso de que estamos falando aqui. Meu problema é que não consigo definir o estado na classe base. Estou no TS 2.4.1. Você por acaso tem o id do problema para que eu possa verificar?

Você sempre pode chamar setState (em componentWillMount).

@pawelpabich Novamente, isso não é um problema :) você não pode atribuir o estado da classe base de propósito . Como você pode? você não conhece o contrato prop sendo usado pelo componente derivado.

interface BaseCompState {
    baseState1?: string;
}

class BaseComp<TState extends BaseCompState> extends React.Component<any, TState> {
    constructor(props) {
        super(props);
        this.state = {
            baseState1: "fromBase",
        };
    }
}

interface TopCompState extends BaseCompState {
    topState1?: string;
}

class TopComp extends BaseComp<TopCompState> {
    constructor(props) {
        super(props);
        this.state = {
            baseState1: "fromTop",
            topState1: "fromTop",
        };
    }
}

Esse é um exemplo simples de um componente derivado (props omitidos, mas mesma ideia). o this.state = na classe base obviamente não pode funcionar, porque não sabe o que é TState . além disso, se funcionasse, estaria apenas sobrescrevendo o estado definido pelo pai. O estado final seria { baseState1: "fronBase" } . O que aconteceu com a propriedade topState?

Se você estiver absolutamente convencido de que precisa lidar com o estado em seu componente base, poderá passar o estado do componente derivado para o construtor do componente base (como TState para poder atribuí-lo) - isso pode ser algo como esta:

interface BaseCompState {
    baseState1?: string;
}

class BaseComp<TState extends BaseCompState> extends React.Component<any, TState> {
    constructor(props, state: TState) {
        super(props);
        this.state = Object.assign({
            baseState1: "fromTop",
        }, state);
    }
}

interface TopCompState extends BaseCompState {
    topState1?: string;
}

class TopComp extends BaseComp<TopCompState> {
    constructor(props) {
        super(props, {
            topState1: "fromTop",
        });
    }
}

Ou ainda mais simples, você pode chamar this.setState( de dentro do seu componente base (sim, você pode fazer isso no construtor!)

Não há problema aqui.

@caesay Concordo plenamente que, se não houver restrições, a atribuição não faz sentido. Mas o código a seguir ainda gera erros de compilação, embora o compilador tenha todas as informações necessárias para verificar se o código está correto.

import * as React from "react";

/* tslint:disable:max-classes-per-file*/

interface BaseProps {
    baseProp: string;
}

interface BaseState {
    baseState: string;
}

class Base<TProps extends BaseProps, TState extends BaseState> extends React.Component<TProps, TState> {
    constructor(props) {
        super(props);

        this.state = {
            baseState: props.baseProp
        };
    }

    render() {
        return <div>{this.state.baseState}</div>;
    }
}

interface DerivedProps extends BaseProps {
    derivedProp: string;
}

interface DerivedState extends BaseState {
    derivedState: string;
}

export class Derived extends Base<DerivedProps, DerivedState> {
    constructor(props) {
        super(props);

        this.state = {
            derivedState: props.derivedProp
        };
    }

    render() {
        return <div>{this.state.derivedState}</div>;
    }
}

Erros

webpack: Compiled successfully.
ERROR at Test.tsx(17,9):
TS2322: Type '{ baseState: any; }' is not assignable to type 'Readonly<TState>'.

ERROR at Test.tsx(39,9):
TS2322: Type '{ derivedState: any; }' is not assignable to type 'Readonly<DerivedState>'.
  Property 'baseState' is missing in type '{ derivedState: any; }'.

Version: typescript 2.4.1

Primeiro. Seus adereços na base no construtor não são digitados. Assim props.baseProp é any , que não é atribuível!

Segundo, seus adereços em Derived têm o mesmo problema E você está perdendo baseState . O que obviamente não funcionará, independentemente de Readonly

TProps extends BaseProps o que significa que TProps tem pelo menos os mesmos membros que BaseProps . Então, como isso não é definido? Eu entendo que o compilador pode não ser capaz de inferir isso, mas dizer que não está definido não parece correto. O mesmo pensamento pode ser aplicado a Derived .

@caesay setState no construtor não é uma solução confiável porque esse método é assíncrono e você ainda pode chegar a render sem o estado inicial definido.

A única solução confiável que posso ver é definir todo o estado nas classes derivadas. Isso tem uma desvantagem óbvia que:

  1. Isso precisa ser duplicado em cada classe derivada
  2. As classes derivadas precisam saber sobre o estado com o qual não se importam.

O exemplo que mostrei acima funcionaria em C#, então seria bom se pudesse funcionar em TypeScript.

  1. ~setState é seguro no construtor~
  2. No caso de uma classe derivada, o melhor caso que posso ver é chamar setState no seu componentWillMount . Sua base não sabe o que deve estar no estado para seu filho, portanto, não pode colocar this.state em uma configuração segura. No entanto, sua subclasse pode chamar o componentWillMount do pai e, em seguida, definir o estado que achar necessário.
  3. Existem recursos de linguagem em muitos idiomas que seria bom ter em texto datilografado. Alguns são viáveis. Outros não são. De qualquer forma, não é um argumento para sua inclusão.
  4. Os erros que você está vendo fazem sentido. Eles não sugerem um bug no texto datilografado nem nas datilografias. Em cada caso, você está literalmente tentando atribuir this.state a um objeto que não corresponde ao tipo esperado.

EDITADO, para refletir que eu estava incorreto sobre setState no construtor e para adicionar acentos graves para facilitar a leitura.

@ericanderson Acho que não estamos fazendo nenhum progresso aqui. Mostrei um exemplo e agradeceria se pudéssemos nos concentrar nele. Caso contrário, é difícil ter uma discussão.

Re setState não é seguro usar no construtor. Ele não lança um erro, mas não define o estado antes que a renderização aconteça. Eu tenho código que quebra por causa disso e os documentos do React são muito claros que não devem ser usados ​​lá.

@pawelpabich Não, este não é o lugar para esse argumento. Você está fundamentalmente errado em sua compreensão do idioma. No exemplo que você forneceu, você não satisfez o contrato do "Estado" em NENHUMA de suas atribuições para o estado.

Por exemplo, quando você faz

this.state = { baseState: props.baseProp };
// now the state is exactly { baseState: props.baseProp }

O estado é exatamente { baseState: props.baseProp } e isso NÃO satisfez o requisito de TProps extends BaseProps (porque não sabemos o que é TProps! poderia ter quaisquer propriedades nele).

Depois disso, você está fazendo uma tarefa _SEPARADA_ .

this.state = { derivedState: props.derivedProp };
// now the state is exactly {  derivedState: props.derivedProp }

o estado agora é exatamente { derivedState: props.derivedProp } (você sobrescreveu sua atribuição de estado base!!) e isso não satisfaz DerivedState OR BaseProps.

Você está totalmente equivocado ao pensar que isso deveria funcionar. Se você tiver um problema com a forma como a atribuição básica de variáveis ​​funciona, converse com os designers de linguagem em uma nova edição e seja abatido por lá, para que paremos de receber notificações aqui, por favor.

Como uma nota lateral - você TAMBÉM está substituindo seu método render() base, o que significa que seu componente base não poderá renderizar nada. Se você estiver convencido de que é isso que deseja, poderá adicionar um membro protegido getBaseState() e chamá-lo do construtor derivado ao definir o estado (para que não seja necessário duplicar a lógica do estado base). Mas o que eu acho que você realmente quer é não usar componentes derivados. Tente reestruturar para usar composição (onde você tem um objeto contendo vários objetos filho). Eu acho que você vai descobrir que vai ficar muito mais limpo.

Eu dificilmente quero me afastar da leitura para criar um novo projeto só para debater isso com vocês, mas infelizmente...

Vou ficar corrigido sobre setState () no construtor, mas isso não muda como me sinto sobre usá-lo em componentWillMount .

Exemplo de trabalho de como isso seria feito:
https://github.com/ericanderson/set-state-example

Especificamente, index.tsx:

import * as React from "react";
import * as ReactDOM from "react-dom";

/* tslint:disable:max-classes-per-file*/

interface BaseProps {
  baseProp: string;
}

interface BaseState {
  baseState: string;
}

class Base<TProps extends BaseProps, TState extends BaseState> extends React.Component<TProps, TState> {
  public componentWillMount() {
    this.setState({
      baseState: this.props.baseProp,
    });
  }

  public render() {
    return (
      <p>
        <code>this.state.baseState: </code>
        {this.state.baseState}
      </p>
    );
  }
}

interface DerivedProps extends BaseProps {
  derivedProp: string;
}

interface DerivedState extends BaseState {
  derivedState: string;
}

export class Derived extends Base<DerivedProps, DerivedState> {
  public componentWillMount() {
    super.componentWillMount();
    this.setState({
      derivedState: this.props.derivedProp,
    });
  }

  public render() {
    return (
      <div>
        <p>
          <code>this.state.derivedState: </code>
          {this.state.derivedState}
        </p>
        {super.render()}
      </div>
    );
  }
}

ReactDOM.render(<Derived derivedProp="its derived" baseProp="its basic" />, document.getElementById("main"));

@pawelpabich se você quiser implementar um componente polimórfico com um estado inicial, precisará tornar seu componente base abstrato e criar uma função abstrata getInitialState() (ou com tema semelhante) para implementar em sua classe derivada. Você só quer atribuir o estado uma vez, seja no construtor ou com setState como @ericanderson mostrou.

abaixo está o seu exemplo convertido em uma solução totalmente polimórfica, com separação completa de preocupações com relação à construção do estado:

interface BaseProps {
  baseProp: string;
}

interface BaseState {
  baseState: string;
}

abstract class Base<TProps extends BaseProps, TState extends BaseState> extends React.Component<TProps, TState> {
  constructor(props: TProps) {
      super(props);

      this.state = this.getInitialState();
  }

  protected abstract getInitialState(): TState;

  protected getBaseState() {
    return this.props.baseProp;
  }

  render() {
      return <div>{this.state.baseState}</div>;
  }
}

interface DerivedProps extends BaseProps {
  derivedProp: string;
}

interface DerivedState extends BaseState {
  derivedState: string;
}

export class Derived extends Base<DerivedProps, DerivedState> {
  getInitialState(): DerivedState {
    return {
      baseState: this.getBaseState(),
      derivedState: this.props.derivedProp,
    };
  }

  render() {
      return <div>{this.state.derivedState}</div>;
  }
}

@patsissons obrigado!

@caesay Admito que estava errado e por algum motivo não vi que as atribuições vão se sobrepor. Dito isto, o uso de CAPS e ! não me ajudou a sair do meu buraco.

@patsissons e @ericanderson focaram no problema e agora temos uma solução que outros podem usar.

@pawelpabich Concordo que meus maneirismos eram menos que profissionais - mas é compreensível, considerando que lhe dei várias explicações, amostras etc., e você optou por não me ouvir.

então seria apenas sobrescrever o estado definido pelo pai.

[_se você quiser_] manipular o estado em seu componente base, você pode passar o estado do componente derivado para o construtor do componente base

[_se você quiser manipular o estado em seu componente derivado_] você pode adicionar um membro protegido getBaseState() e chamá-lo do construtor derivado ao definir o estado.

O que @patsissons fez foi pegar os comentários já mencionados aqui e fornecer uma amostra de código - o que não deveria ser necessário. Isso não é stackoverflow, e geralmente também não fornecemos amostras de código prontas.

Eu sou novo para reagir e digitar, talvez eu não saiba sth, mas mesmo que o aplicativo seja compilado sem erro, aviso e dica, recebo um erro de tempo de execução. Abaixo está um componente de exemplo. Eu atribuo o erro ao estado Readonly . Se o aplicativo funcionou antes da alteração Readonly , após essa alteração ele parou de funcionar e não apresenta erros de tempo de compilação.

import * as React from 'react';

export default class HomePage extends React.Component<any, Map<string, string>> {

  public componentWillMount() {
    const map = new Map<string, string>();
    map.set('aKey', 'aValue');
    this.setState(map);
  }

  public render() {

      return (
        <div className="home">
          <div className="greeting">
            Home page: {this.state.get('aKey')} // <-- I get an error here
          </div>
        </div>
      );
  }
}

O erro:

homePage.tsx:12 Uncaught TypeError: this.state.get is not a function
    at HomePage.render (homePage.tsx:12)
    at eval (ReactCompositeComponent.js:793)
    at measureLifeCyclePerf (ReactCompositeComponent.js:73)
    at ReactCompositeComponentWrapper._renderValidatedComponentWithoutOwnerOrContext (

O estado deve sempre ser um objeto de chave simples afaik, então, em vez disso, defina o estado
algo como: { values: Map <string, string> } e leia
this.state.values.get('aKey')

Op vr 29 set. 2017 às 09:01 schreef Janusz Białobrzewski <
[email protected]>:

Eu sou novo para reagir e datilografar, talvez eu não saiba nada, mas mesmo
embora o aplicativo seja compilado sem erro, aviso e dica, recebo um tempo de execução
erro. Abaixo está um componente de exemplo. Eu atribuo o erro a Readonly
Estado. Se o aplicativo funcionou antes da alteração Readonly, depois disso
alterá-lo parou de funcionar e não dá erros de tempo de compilação.

import * como React de 'react';
exportar a classe padrão HomePage estende o React.Component> {

public componentWillMount() {
const mapa = novo mapa();
map.set('aKey', 'aValue');
this.setState(mapa);
}

renderização pública() {

  return (
    <div className="home">
      <div className="greeting">
        Home page: {this.state.get('aKey')} // <-- I get an error here
      </div>
    </div>
  );

}
}

O erro:

pagina inicial. tsx:12 Uncaught TypeError: this.state.get não é uma função
em HomePage.render (homePage.tsx:12)
em eval (ReactCompositeComponent.js:793)
em MeasureLifeCyclePerf (ReactCompositeComponent.js:73)
em ReactCompositeComponentWrapper._renderValidatedComponentWithoutOwnerOrContext (


Você está recebendo isso porque foi mencionado.
Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/DefinitelyTyped/DefinitelyTyped/issues/14250#issuecomment-333047367 ,
ou silenciar o thread
https://github.com/notifications/unsubscribe-auth/ABvGhM5hDyRNyUeZuIiGeTZk1N-rfuA4ks5snJW5gaJpZM4LuDWV
.

Obrigado, mas parece ser um esforço inútil declarar o estado como Readonly<S> , pois seus membros aninhados não são afetados pelo Readonly.

É possível que um dia Readonly seja aplicado recursivamente, mas por enquanto, cabe a você ter certeza de que lidou com isso corretamente. No seu caso, você realmente deve declarar ReadonlyMap ou

interface State {
    readonly [key: string]: string;
}

ou aninhado:

interface State {
    map: { readonly [key: string]: string };
}

Podemos usá-lo apenas para leitura profunda:

export type DeepReadonly<T> =
  T extends Array<any> ?
  ReadonlyArray<T[0]> :
  T extends Date ?
  T :
  T extends Function ?
  T :
  T extends object ?
  { readonly [P in keyof T]: DeepReadonly<T[P]> } :
  T;

export type Writable<T> =
  T extends ReadonlyArray<any> ?
  Array<WritableObject<T[0]>> :
  T extends Array<any> ?
  Array<WritableObject<T[0]>> :
  WritableObject<T>;

type WritableObject<T> =
  T extends Date ?
  T :
  T extends Function ?
  T :
  T extends object ?
  { -readonly [P in keyof T]: Writable<T[P]> } :
  T;
Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

csharpner picture csharpner  ·  3Comentários

ArtemZag picture ArtemZag  ·  3Comentários

tyv picture tyv  ·  3Comentários

Loghorn picture Loghorn  ·  3Comentários

jbreckmckye picture jbreckmckye  ·  3Comentários