Definitelytyped: React.d.ts Solo lectura<t>en estado y accesorios</t>

Creado en 25 ene. 2017  ·  91Comentarios  ·  Fuente: DefinitelyTyped/DefinitelyTyped

Hola @ericanderson

Tengo muchos problemas con este cambio cuando se usa en la práctica:

Problema 1: Ir a la definición

Cuando presiona Ir a definición en una propiedad de accesorios o estado, TypeScript no puede resolverlo.

interface MyComponentProps {
    name: string;
}

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

image

Tiene sentido porque el miembro se genera sintéticamente, pero de todos modos es molesto.

Problema 2: Jerarquías de componentes (P Genérico con restricciones)

Más importante, si creas un componente abstracto como este:

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 puede mostrar que hay una propiedad en Cambio, pero a veces no puede descubrir su tipo.

image

Este es el cambio más importante ya que me impide tener jerarquías de componentes que comparten accesorios y funcionalidades comunes. Parece un problema en el compilador de TS, pero hasta que se solucione.

Problema 3: no tan de solo lectura.

Si bien estoy de acuerdo en que este cambio captura bien la intención funcional de React, hay situaciones válidas en las que puede modificar el estado de manera imperativa, como en el constructor, y también si cambia el estado y llama a forceUpdate, todo funciona bien.

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.

¿Es recomendable? No.
¿Está prohibido? Tampoco, de lo contrario forceUpdate no existirá.

Por supuesto, podría convertir el estado en S (o any ) y realizar el cambio, pero si es un patrón común, se vuelve engorroso.

Conclusión: ¿Vale la pena?

Me entristece que la nueva característica brillante de TS cause más problemas que soluciones en este caso, pero honestamente creo que este es el caso aquí.

Por otro lado, el cambio de setState es genial 👍, no sabía de Pick<S,K> .

Comentario más útil

El problema 3 está en debate, supongo.

Tiene razón en que puede _técnicamente_ hacer el ejemplo anterior en React, pero definitivamente diría que no es la forma en que se pretendía usar React.

Esto se puede dividir en 3 casos distintos.

Inicialización genérica

interface State {
  bar: number;
}

interface Props {
  baz: number;
}

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

Inicialización basada en props

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,
    });
  }
}

Asignación aleatoria con forceUpdate

Dado que creo que es mejor empujar a las personas hacia lo "correcto", puede solucionar este problema fácilmente al volver a declarar public state :

interface State {
  bar: number;
}

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

Todos 91 comentarios

¿Qué versión de mecanografiado está utilizando su estudio visual?

@vsaio para sa

Para el problema 1, con TS 2.1.5 y el último VSCode, esto funciona bien para mí. No tengo Windows/VS, así que no puedo verificar allí, pero apostaría que hay actualizaciones para sus complementos o que no está en TS 2.1.5

Lo mismo para el problema 2

VS 2015 con TS 2.1.5.0

El problema 3 está en debate, supongo.

Tiene razón en que puede _técnicamente_ hacer el ejemplo anterior en React, pero definitivamente diría que no es la forma en que se pretendía usar React.

Esto se puede dividir en 3 casos distintos.

Inicialización genérica

interface State {
  bar: number;
}

interface Props {
  baz: number;
}

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

Inicialización basada en props

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,
    });
  }
}

Asignación aleatoria con forceUpdate

Dado que creo que es mejor empujar a las personas hacia lo "correcto", puede solucionar este problema fácilmente al volver a declarar public state :

interface State {
  bar: number;
}

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

Mis problemas son con la variación de los genéricos. específicamente para escribir dentro de la clase que se escribe genéricamente. a continuación hay una muestra bastante mínima de dónde se descomponen las cosas.

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);

Estoy en TS 2.1.5.0

image

pero podría ser que en VS tengamos una peor experiencia con TS que en código VS...

para el Problema 1, vaya a la definición TS tampoco funciona en 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 el Problema 2 es cierto que VS Code se comporta mejor:

image

mientras que VS parece confundido:

image

Creo que para VSCode y el problema 1, funciona porque estoy usando el complemento para "La última gramática de Typescript y Javascript", que debe tener un manejo más inteligente.

@patsissons ese es un ejemplo interesante, aunque creo que es más representativo de un error en mecanografiado que un error en el archivo de definición. Por ejemplo, setState solía tomar S lo que significaba que para hacer parciales teníamos que hacer trucos extraños como setState({foo:5} as any as State) o usar el que toma una función. No estoy seguro de que la falta de expresividad del compilador haga que los tipos sean "incorrectos". Creo que este es un argumento decente para un cambio en el LÉAME para marcar este caso límite.

¿Ha presentado un problema en TS?

Entonces, este cambio hoy en día rompe todos los VS y deshabilita Ir a definición en todos los Códigos VS, excepto si tiene un complemento ...

También está el argumento de la integridad. Hay millones de API que están destinadas a ser de solo lectura y no lo son hoy en día, solo en 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;
    }

Creo que readonly debería usarse para 'freeze' o 'Inmmutable.js', no para la cola larga de pensamientos que no están destinados a ser modificados, como objetos de eventos, por ejemplo.

No lo he presentado, solo actualicé mi código hoy para manejar los nuevos tipos Readonly<T> , este fue un caso con el que me encontré y no tenía una solución escrita correctamente. Continúe y presente un problema, estaré ocupado la mayor parte del resto del día hoy con el código de parcheo.

Ah sí, sabía que me perdí algunos. @olmobrutall Si mantenemos los cambios de estado que introduje para marcar como de solo lectura, acepto que esos métodos deberían actualizarse. Sin embargo, siento que primero necesitamos un consenso sobre qué es lo correcto.

En cuanto a los descansos de VS, no sé qué es lo correcto. ¿Deberían retenerse los tipos porque algunas herramientas no se mantienen actualizadas?

@patsissons Siempre puede proporcionar sus propios tipos para reaccionar por ahora si desea esperar a ver cómo funciona esto antes de actualizar todo su código. https://ericlanderson.com/using-custom-typescript-definitions-with-ts-2-x-3121db84015d#.ftlkojwnb

en nuestra experiencia, VS siempre está un poco atrasado. Nuestra tienda usa vscode para realizar cualquier desarrollo de mecanografiado activo y VS se usa más simplemente para parchear archivos de código o para que los desarrolladores que no son mecanografiados revisen el código, no necesariamente para el desarrollo activo.

@ericanderson el truco no es tan malo por ahora, solo tengo que ganar Readonly<T> para obtener mi T que se puede asignar a Readonly<Base> .

Hablamos de 'react.d.ts', esta declaración de miembro único se usa masivamente. Creo que vale la pena esperar hasta que VS esté listo.

Además, como el 50% de los tipos en el mundo están destinados a ser de solo lectura, como los objetos que obtienes de las API, no creo que debamos anotar eso.

Creo que Readonly debería usarse para objetos que se han convertido explícitamente para tener propiedades de solo obtención. Como congelar.

@olmobrutall Readonly es nuevo, por lo que la mejor práctica exacta no está realmente definida. Personalmente, preferiría que todo declarara que se necesita un Readonly<> de cosas para ayudar a indicar que no lo mutará. De manera similar, React no espera que modifique state fuera de setState y, por lo tanto, este cambio garantiza que los accidentes no introduzcan errores, que es uno de los principales beneficios de usar TypeScript en lugar de javascript.

Si el rendimiento fuera más consistente en todos los navegadores para Object.freeze , me imagino que la gente de React realmente comenzaría a congelarse después setState .

¿Cuál es el propósito de forceUpdate entonces?

Tengo curiosidad por los pensamientos de otras personas sobre cómo debería funcionar DefinitelyTyped con respecto a las actualizaciones de herramientas, así como la filosofía sobre Readonly on react (y otras bibliotecas cuya intención es que no modifique ciertos objetos).

cc/ @johnnyreilly @vsaio @pspeter3 para conocer sus pensamientos sobre reaccionar específicamente y otros pensamientos en general
cc/ @andy-ms @mhegazy para obtener ideas sobre cómo DefinitelyTyped debería proceder filosóficamente para las actualizaciones de herramientas y el uso celoso de Readonly

@olmobrutall usamos forceUpdate para poner en cola un procesamiento en el lado de reacción, impulsado por eventos observables en el lado del estado.

ACTUALIZAR :
Aclararé un poco nuestro escenario para que no se malinterprete. Nuestros objetos de estado son objetos inmutables de larga duración (por lo que Readonly<T> es realmente muy adecuado para nosotros). Estos objetos de estado contienen múltiples flujos observables rxjs que se canalizan hacia una notificación observable llamada stateChanged . Los componentes de React observan este observable en busca de eventos y canalizan esos eventos en una llamada a forceUpdate (después del rebote). En efecto, nuestro estado mutable vive dentro del estado, pero el estado mismo y los miembros que existen en el estado son todos inmutables. Ciertamente, este no es el caso de uso estándar para React, pero es un flujo muy similar. Simplemente tenemos objetos de estado inteligente que saben cómo informar a los componentes cuando se requiere una nueva representación.

@ericanderson, el problema principal es que estas definiciones de tipo sufren problemas de SemVer. Debido a que las versiones de definición de tipo están vinculadas en gran medida a sus respectivas versiones de módulo, terminamos con un aumento de versión menor que genera cambios de definición de tipo de ruptura, lo que significa que tenemos que anclar versiones de @types en nuestro package.json expediente.

@olmobrutall De los documentos de reaccionar:

Normalmente, debe intentar evitar todos los usos de forceUpdate() y solo leer desde this.props y this.state en render().

De hecho, la guía de reacción le dice que no actualice el estado directamente: https://facebook.github.io/react/docs/state-and-lifecycle.html#do -not-modify-state-directly

forceUpdate , como lo leí, es solo para forzar la actualización de su componente cuando su componente se basa en datos _no_ en sus accesorios o su estado.

@patsissons Puedo estar equivocado, pero creo que SemVer está diseñado para ser compatible con versiones anteriores de API e intenciones semánticas. El hecho de que use una biblioteca de una manera no prevista (según los documentos) no significa que la biblioteca deba seguir admitiendo dichos usos no previstos. Los autores de la biblioteca están bien dentro de SemVer para cambiar la semántica que era incorrecta pero que algunas personas usaban.

Dicho esto, tal vez Readonly<> a state es un cambio demasiado grande, pero supongamos por un momento que es el cambio correcto. ¿Cuándo debería publicarse en DefinitelyTyped? Tu código siempre sufrirá la necesidad de cambiar una vez que recibas la actualización que finalmente marque state como Readonly<> .

Todavía no sé qué tiene de correcto aplicar Readonly<> a state lo que hace que sea difícil debatir sobre semver, herramientas o cualquier otra cosa. Mi instinto era que tenía razón. Las personas que revisaron el cambio nunca lo mencionaron como un problema. Parece estar en línea con la intención del equipo de React.

Estoy feliz de deferir a cualquiera de los revisores para reaccionar en DefinitelyTyped (los cc'd a todos arriba).

Entonces, ¿el Observable cambia el estado y usted fuerza la actualización? Entonces, cambiar el estado de manera imperativa está permitido de alguna manera.

Entiendo que no está definido al 100 % dónde se debe usar Readonly. Pero, ¿necesitamos comenzar con una propiedad controvertida y de uso masivo antes de que las herramientas estén listas?

Estoy totalmente a favor de tipado fuerte, mantengo 6 proyectos, todos con estrictos NullChecks, pero los beneficios aquí son mucho menores que los problemas que produce actualmente.

@ericanderson Creo que SemVer2 está diseñado para permitir declaraciones de versión de nodo como ^15.0.0 y esperar que cualquier actualización menor o parche (es decir, 15.0.1 o 15.1.0 ) al módulo sea transparente o al menos compatible con versiones anteriores desde una perspectiva externa. Cualquier actualización importante ( 16.0.0 ) requeriría un ajuste en la declaración de la versión para introducir el cambio. Básicamente, esto evita que los cambios importantes se introduzcan en el sistema de escritura. Pero actualmente, las versiones de definición de tipos no pueden desviarse de sus respectivas versiones de módulos versión principal (por convención), lo que da como resultado esta discontinuidad.

La versión corta es que las definiciones de tipo pueden tener cambios importantes introducidos sin que el propio módulo cambie en absoluto, y los cambios importantes requieren un cambio importante de versión.

Pero no harás una actualización de fuerza de eliminación de relaciones públicas, ¿verdad?

Entonces, si forceUpdate está allí, cambiar el estado de manera imperativa también debería estar allí.

En teoría, debe usar un gráfico de estado inmutable profundo, pero muy a menudo cambiar el Estado de manera imperativa está bien y no todos los desarrolladores aceptan la idea de las estructuras de datos persistentes.

Afortunadamente, React permite una ruta de escape y hace posibles los cambios directos en el estado, ¿vamos a prohibir a los desarrolladores de TS que tomen esa ruta? ¿No es demasiado paternalista?

Vue.js, por ejemplo, promueve los cambios imperativos, no me sorprendería si influye en React.

También estaba leyendo una publicación de blog de un autor de React no hace mucho (puedo recordar) animando a usar React sin toda la ceremonia de Redux.

De lo contrario, mi posición es publicar las definiciones de tipos lo antes posible, mi única preocupación es la automatización. dado que, dado el estado actual de la definición de tipo, el control de versiones de una compilación sucesiva sin cambios en la fuente puede fallar. Estos tipos de fallas de CI no deterministas son preocupantes. Nadie quiere ver que su compilación se rompa porque impulsaron un cambio y luego descubren que su mano de cambio no tiene nada que ver con la falla de la compilación.

Después de dormir en él, mis opiniones personales son las siguientes:

  • Una buena práctica implicaría usar bloqueos de hilo o npm, por lo que no recibiría una sorpresa a menos que primero actualice localmente.
  • Hacer estado de solo lectura es cómo se pretende usar React. La documentación y los ejemplos lo confirman.
  • El flujo de trabajo en el que no desea usar setState está dentro de su base de código y dentro de sus propios derechos. Tiene razón en que React proporciona forceUpdate, pero su uso está destinado a causar un procesamiento cuando se encuentra fuera del caso de uso previsto. Por lo tanto, si no desea utilizar el estado según lo previsto, está bien, pero en ese momento no necesita utilizar el estado de la variable de instancia. De hecho, solo puede usar variables privadas regulares.
  • Sí, muchas personas dependen de este proyecto y, sin embargo, hasta ahora estas son las dos únicas quejas que me hacen pensar que no se trata de un problema generalizado. Además, el problema planteado sobre la función global se puede reescribir para tomar el genérico de manera diferente (ver el problema de TypeScript vinculado)

Teniendo en cuenta los pensamientos anteriores, así como las soluciones alternativas para las aplicaciones React no estándar, creo que Readonly es correcto y el único cambio necesario para completar es actualizar los métodos del ciclo de vida para que coincidan.

Estoy de acuerdo en que estos cambios tienen mucho sentido, mi caso de uso que estaba causando problemas era un caso de esquina muy singular que rara vez debería encontrarse. Al adaptar mi base de código a accesorios y estados de solo lectura, detecté algunos problemas de escritura que de otro modo serían indetectables. No hay duda de que publicar los cambios fue la elección correcta.

Patsisson, usando VS, VS Code o cualquier otro editor?

Mi punto es que, si bien React promueve un enfoque funcional, permite un flujo de trabajo similar al de un videojuego en el que realiza cambios en el mundo de forma imperativa (estado) y luego renderiza (forceUpdate). Este enfoque ahora está prohibido en TS. Tipo de func-damentalismo :)

Pensaré en alternativas para hacer que mi ecosistema actual funcione entonces...

Error de lanzamiento del problema 2 solo con strictNullChecks .

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

+1 estoy usando estrictosNullChecks

@ericanderson ?

Como se indicó anteriormente, esto está relacionado con las herramientas, que claramente está fuera del alcance de DT. Si está en VSCode e instala la vista previa del próximo analizador TS, no vi este problema con strictNullChecks cuando estaba escribiendo cualquiera de los anteriores.

No tengo ventanas, así que no puedo hablar con VS correctamente.

este parche Pick rompió las sugerencias en VSCode. al hacer this.setState({ | }) (Ctrl + Espacio), no se muestra nada, aunque el estado está claramente definido y se usa Partial<State> porque setState puede establecer el estado de los miembros de forma selectiva

En mi humilde opinión, el código correcto debería ser setState(state: Partial<S>, callback?: () => any): void;

Como se discutió en la rama de solicitud de extracción original, comenzamos con Parcial. Sin embargo, si su objeto de estado es:

Estado de la interfaz {
foo: cadena;
}

Entonces con parcial podrías hacer lo siguiente:

setState({foo: indefinido});

Lo cual es claramente incorrecto.

Lo siento, pero de nuevo sobre Readonly

React no es solo Redux y setState. React también es mobx y otros patrones observables, donde la asignación de propiedades de estado es la CARACTERÍSTICA PRINCIPAL . El cambio discutido mata por completo el uso de mobx con mecanografiado.

Entonces, ¿por qué agregar el comportamiento que no existe en el código de reacción original al archivo .d.ts? .d.ts debe ser un reflejo de la biblioteca original, pero no enseñar a las personas el estilo de codificación correcto, ¡de acuerdo con el punto de vista del autor!

@lezious , me temo que no entiendo tu posición. ¿Puede proporcionar una muestra de código y lo que está roto en los tipos con respecto a la muestra? ¡Gracias!

No hay problema:

esta es mi clase estatal

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;
}

y este es mi 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;
            });
    }
   ....

}

y ahora nosotros (nuestra empresa con un gran proyecto escrito en react+mobx) actualizamos el DT y React al comienzo del nuevo ciclo de lanzamiento y... más de 3000 errores de compilación "la propiedad es de solo lectura". Guau. ¿Qué me sugiere que haga: reescribir todo el proyecto en redux, nunca actualizar react.d.ts o siempre mantener y admitir la versión bifurcada?

@mweststrate , por favor revisa esto.

@Iezious Aprecio tu posición y te pido que te calmes. Estoy tratando de trabajar contigo. Esto no tiene nada que ver con Redux, sino puro React.

No quiero que DT bloquee un caso de uso que funcionó anteriormente, sin embargo, no creo que la forma en que describe el uso de mobx con reaccionar sea consistente con la documentación de reacción (ni siquiera la documentación de mobx ahora que he leído sobre eso).

React establece claramente en la documentación que hay 3 formas de usar el estado correctamente, y la primera es "No modificar el estado directamente".

Esto me lleva a creer que la forma en que su código base funciona actualmente es muy probable que se rompa en futuras versiones de reaccionar. Al revisar https://github.com/mobxjs/mobx-react , no veo ninguna sugerencia de que use el estado de esta manera. De hecho, parece que quieren que uses propiedades.

Al revisar https://mobx.js.org/getting-started.html y buscar en Google "estado de reacción de mobx", no encuentro ninguna documentación que sugiera que use mobx de la forma en que lo está haciendo.

Se supone que DT transmite el espíritu de la biblioteca subyacente en el mejor de los casos y la implementación real en el peor y está claro que comprar el componente de reacción y extender significa respetar el contrato implícito.

No estoy seguro de lo que te sugiero que hagas. Algunas opciones que puedo pensar en la mano:

  1. Una opción "barata", si insiste en hacerse cargo de la variable state es buscar y reemplazar React.Component con MyComponent y definir MyComponent como una subclase de React.Component sin las restricciones de solo lectura.
  2. Otro, basado en los ejemplos idiomáticos publicados en la documentación de mobx, es tomarse el tiempo para dejar de usar this.state y solo usar variables en los React.Component reales. Esto puede ser un poco doloroso, pero al menos las personas nuevas en su proyecto podrán ver los patrones en su base de código tal como se describen en línea.
  3. Podría volver a declarar state en cada componente si desea seguir haciéndolo de manera similar a como lo está haciendo.
  4. Puede buscar y reemplazar this.state con this.somethingElse y declarar manualmente.
  5. Podría dejar de tomar actualizaciones para reaccionar desde DT (y posiblemente en el futuro de reaccionar en general, dependiendo de cómo los cambios futuros puedan afectar su caso de uso).

Si fuera mi proyecto, probablemente haría el número 2, aunque no sé lo suficiente sobre mobx para estar seguro.

Lo siento, no pude llegar a estar de acuerdo contigo (no significa que otros no estén de acuerdo contigo). Traté de encontrar una razón para revertir esa parte, pero parece que no puedo subir a bordo en este momento.

Mencionaré nuevamente nuestra estrategia, que es una aplicación personalizada de observables RxJs para impulsar los cambios de estado de React y la representación que se parece mucho al patrón mobx. Usamos acciones para recibir información de la capa de vista (Reaccionar). Las acciones son sinónimo de una función que consume entrada y produce un observable, que luego impulsaría otros observables de estado. Este patrón permite que el estado permanezca inmutable desde la perspectiva de la capa React, ya que solo consulta valores observables y ejecuta acciones de estado. Internamente, su estado puede "mutarse" como resultado de las acciones, ya que el estado interno no tiene restricciones de solo lectura.

No puedo calmarme. Tengo el proyecto en producción y necesito dedicar una gran cantidad de tiempo a los equipos, y esto significa dinero desde este cambio.

¿Y cuál es la razón? ¿Este cambio refleja la realidad en reaccionar? No. Agrega las restricciones y el comportamiento que no existe en reaccionar, la restricción que se agrega de alguna manera solo porque piensa que esto es correcto.

¿Cuál es el objetivo del proyecto DT? ¿Describir las bibliotecas JS con la mayor precisión posible, o describir nuestra visión de la forma de uso correcto de esas bibliotecas? Según el nombre "Definitely Typed" es el primero. Entonces, si esta restricción no existe en la biblioteca JS original, NO DEBE existir también en DT. Este es mi punto. ¿Dónde me equivoco en este punto?

Entiendo que esté frustrado, sin embargo, esta es la forma en que se pretendía usar la reacción al leer los documentos. Difícilmente veo cómo deberíamos hacer que DT sea menos específico porque su equipo abusó de la biblioteca y violó el contrato implícito.

Muéstrame una onza de documentación publicada por el equipo de reacción que sugiera que el estado debería ser directamente mutable e inmediatamente volveré a cambiar el código.

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

Nunca modifique this.state directamente, ya que llamar a setState() después puede reemplazar la mutación que realizó. Trate este estado como si fuera inmutable.

Parece bastante claro que reaccionar considera this.state inmutable. React no considera las _propiedades_ de this.state inmutables (que es la suposición de redux). Eres libre de hacer:

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

en reacción idiomática.

Mi preferencia es escribir la API con precisión (que en este caso significa Readonly ) y expresar todas las invariantes que establece el equipo de reacción.

@ericanderson lo siento, acabo de darme cuenta de esto. FWIW Creo que el cambio es razonable y que las herramientas se pondrán al día. Por cierto, ¿ha oído que están considerando desaprobar la sobrecarga setState que toma un objeto? El futuro es el estilo reducido setState por todas las cuentas.

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

No modifique el estado directamente

Por ejemplo, esto no volverá a renderizar un componente:

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

En su lugar, utilice setState():

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

El único lugar donde puede asignar este estado es el constructor.

@johnnyreilly No lo había hecho. Eso es interesante. ¿Fuente?

Fue cubierto en una de las charlas en la reciente conferencia de reacción. Está disponible en YouTube. Puede haber sido la charla de Lin Clark. Una de las primeras charlas del día 1: cubriendo los próximos cambios para reaccionar para v16. Fibra, etc.

Lo siento @gaearon , quise decir

La razón por la que mobx está realizando cambios de estado es porque los observables están impulsando las actualizaciones de React, en lugar de _reemplazar_ el estado por completo, el estado se convierte en un motor que impulsa la representación. por lo tanto, al hacer algo como this.state.updating = true; , en realidad está haciendo el equivalente a un reemplazo de estado, pero en cambio, el estado es lo suficientemente inteligente como para activar una nueva representación notificando al componente que el estado se modificó con respecto a su contenido anterior. Estoy de acuerdo en que este no es un uso de React _convencional_, sino un uso de React mucho más completo y de mayor nivel. Yo diría que el uso convencional de React solo es útil para proyectos pequeños con un puñado de componentes. Cuando termina con cientos de componentes, cada uno con múltiples docenas de controladores de mutación reactivos, ya no puede usar de manera confiable las alteraciones de estado React convencionales (es decir, setState) y debe entretener cambios arquitectónicos que involucran estado _smart_ (que es lo que mobx esencialmente hace ).

Dicho esto, entiendo por qué está molesto, porque los cambios de tipeo están afectando un uso más avanzado del sistema React. Las asignaciones de estados observables técnicamente no son estados _mutantes_, sino que invocan eventos observables para el valor RHS. Da la casualidad de que la sintaxis que mobx ha elegido para emitir estos eventos observables entra en conflicto con la intención expresa del estado inmutable de React.

@Iezious si necesita una solución rápida para este tipo de problema, puede salirse con la suya aumentando los tipos de React y refactorizando sus componentes para usar una extensión a las definiciones de tipo React.Component .

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;

y ahora puede crear componentes de estado mutable como componentes regulares, excepto que su miembro state ya no está marcado como readonly .

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

@patsissons sí, esa es exactamente la razón.

No estoy mutando el estado, estoy usando mobx observables, que llama setState para mí, lo estoy haciendo porque mi ENORME código de proyecto parece mucho más claro y comprensible.

Sé que puedo hacer mi componente, también puedo hacer un script en mi servidor npm que siempre revertirá este cambio para nuestra empresa. Puedo usar trucos como "this.state.state.updated" y muchos otros trucos.

Solo quiero decir que este cambio afecta el uso de patrones observables como mobx, que en realidad siguen la forma de reaccionar, pero ahora, dado que este cambio no se puede compilar y necesita algunos trucos y soluciones para funcionar. Y por eso creo que este cambio no está bien.

tal vez en lugar de mi MutableStateComponent sugerido, lo llamamos ObservableComponent que está más alineado con el patrón Observable React.

Si suelta Readonly , las personas que usan los tipos de reacción con reacción regular (y/o cualquier otro sistema de administración de estado además de mobx) están expuestas a errores. No uso mobx en mi gran proyecto y aprecio los errores del compilador cuando alguien comete un error tipográfico y accidentalmente usa this.state.foo = bar .

Si hay una compensación inevitable entre el uso de reacción estándar y el uso de reacción no estándar, los tipos de reacción estándar deberían inclinarse hacia el primero.

Además, si usa mobx de forma idiomática, esto no es un problema.

Si elimina Readonly, las personas que usan los tipos de reacción con reacción regular (y/o cualquier otro sistema de administración de estado además de mobx) están expuestas a errores. No uso mobx en mi gran proyecto y aprecio los errores del compilador cuando alguien comete un error tipográfico y accidentalmente usa this.state.foo = bar.

Entonces, una vez más, estás ENSEÑANDO A ESCRIBIR EL CÓDIGO

Este proyecto no se trata de enseñar a escribir el código, este proyecto es para describir la funcionalidad existente de las bibliotecas JS. La limitación discutida no existe en la biblioteca original y debe eliminarse.

Eso es todo.

@patsissons

Si necesita una solución rápida para este tipo de problema, puede salirse con la suya aumentando los tipos de React y refactorizando sus componentes para usar una extensión de las definiciones de tipo de React.Component.

no es correcto. En el mundo empresarial, de donde soy, no hay "soluciones rápidas". Cuando algo cambia en SDK, o DEBE ser compatible con versiones anteriores, o lleva años. No hay arreglos rápidos en más de 2 millones de líneas de proyecto de código. Son semanas de cambios, pruebas, pruebas de producción A/B, implementaciones para un gran número de personas. Cuesta dinero real. ¿Y todo este gran esfuerzo solo porque alguien agregó un cambio no compatible con versiones anteriores que NO EXISTE EN LA BIBLIOTECA REAL?

¿Por qué crees que forceUpdate todavía existe en la reacción? Están hablando en confs sobre el estilo correcto, pero haciendo los cambios para evitar otras formas de uso. ¿Por qué? Dado que es una gran empresa y saben que las bibliotecas deben ser compatibles con versiones anteriores.

@ericanderson escribió eso

this.state.state.value = 1 

tampoco es legítimo desde su punto de vista. La próxima vez obtendrá la herramienta de TS y agregará la limitación que evitará este código. O haga la clase final del componente, o algo más simplemente porque "es el estilo correcto y evita que las personas cometan errores".

Evitar que las personas cometan errores: es tarea de FB, si quieren hacerlo, pueden agregar fácilmente un proxy y no permitir la mutación de estado. El propósito de DT es agregar descripciones y nada más.

@Iezious

Creo que el punto es que el equipo de React no puede hacer que el estado sea inmutable con JavaScript, pero si pudieran, lo habrían hecho. TypeScript, por otro lado , puede hacer que el estado sea inmutable, por eso se realizó este cambio en las definiciones de tipo. La intención absoluta del equipo de React fue prohibir las modificaciones a los miembros del estado directamente (como lo demuestran sus documentos oficiales sobre el uso correcto del estado ), pero no tenían las construcciones de lenguaje para imponer esa restricción. Esta restricción nunca ha sido desconocida, ha sido bien documentada desde el principio. Para aquellos de nosotros que operamos fuera del uso _convencional_ de React, debemos al menos adherirnos a las recomendaciones de uso oficiales de React. Para mi equipo, eso significó diseñar una solución que nos permitiera impulsar cambios de estado sin mutar directamente el estado. Esto se hizo específicamente para garantizar que no nos encontráramos con problemas como este (aunque este cambio nos afectó levemente, pero solo a través de firmas de funciones y no de diseño fundamental).

Si la refactorización no es posible en su situación, fije @types/react en 15.0.1 antes de realizar el cambio, o simplemente no use @types/react y en su lugar mantenga su propia variante del escriba defs y simplemente modifique la escritura state para Component . Realmente no creo que tengas éxito convenciendo a nadie para revertir el cambio.

forceUpdate existe porque está documentado como la ruta de código recomendada para impulsar la representación cuando se modifica el estado estructural interno (o cuando render() usa datos fuera del estado que son mutables). El uso de forceUpdate está diseñado exactamente para el patrón de uso que usa mi equipo con React.

El equipo de reacción PUEDE hacer que el estado sea inmutable con JS, es fácil. Pero no compatible con versiones anteriores.

Una vez más, es:

this.state.state.value = 1 

legítimo o no?

Yo creo que sí, pero mi opinión ya está clara...

No creo que la conversación sobre mutabilidad/inmutabilidad sea relevante _todavía_. Claramente, el error en el compilador de TS (con respecto a Readonly ) combinado con este cambio hace que los componentes genéricos sean completamente imposibles de usar, rompiendo muchos códigos existentes. ¿Seguramente ese es un caso de uso válido universalmente aceptado y es razón suficiente para revertir esto por ahora?

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;
}

¿Alguien sabe si hay un problema abierto con el equipo de Typescript sobre esto? Parece que no puedo encontrar el problema relevante en su rastreador.

@caesay Ver Microsoft/TypeScript#15501

tengo que iniciar el estado en el constructor, pero tslint muestra "el estado es de solo lectura"...

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

Cómo puedo arreglarlo...............

Usar setState

setState no funciona en el constructor

O considere componentWillMount con setState

Gracias

Hola,

Leí todo el hilo, pero no me queda claro si hay planes para manejar el escenario de @alanwei0 .

Estoy totalmente de acuerdo en que tiene sentido tener state como ReadOnly . Dicho esto, no poder establecer el estado inicial en el constructor complica un poco las cosas porque se llama a render antes de que se componentDidMount .

@pawelpabich usar this.state = { en el constructor no es un problema. Puede asignar variables a readonly en el constructor, y Readonly<T> no impide la asignación (¡nunca!).

interface TInterface {
    test: string;
}

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

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

El único error aquí estará dentro fn , no por Readonly<T> , sino por la palabra clave readonly . De hecho, la última versión de los tipos ni siquiera usa la palabra clave readonly , por lo que en realidad puede asignar el estado en cualquier lugar, simplemente no cambiar las propiedades dentro del estado.

El problema del que hablábamos aquí era un error con el compilador TypeScript que causaba que las propiedades de estado perdieran sus tipos en los componentes heredados. Esto ya se ha solucionado, creo, y si es así, este problema se puede cerrar.

@caesay lo siento, pensé que ese era el caso del que estamos hablando aquí. Mi problema es que no puedo establecer el estado en la clase base. Estoy en TS 2.4.1. ¿Por casualidad tienes la identificación del problema para que pueda comprobarlo?

Siempre puede llamar a setState (en componentWillMount).

@pawelpabich Nuevamente, esto no es un problema :) no puede asignar el estado de la clase base a propósito . ¿Como pudiste? no conoce el contrato de utilería que utiliza el 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",
        };
    }
}

Ese es un ejemplo simple de un componente derivado (se omiten los accesorios, pero la misma idea). el this.state = en la clase base obviamente no puede funcionar, porque no sabe qué es TState . además, si _funcionó_, simplemente estaría sobrescribiendo el estado establecido por el padre. El estado final sería { baseState1: "fronBase" } . ¿Qué pasó con la propiedad topState?

Si está absolutamente convencido de que necesita manejar el estado en su componente base, puede pasar el estado del componente derivado al constructor del componente base (como TState para que pueda asignarlo); eso podría verse así 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",
        });
    }
}

O aún más simple, puede llamar a this.setState( desde su componente base (sí, ¡puede hacerlo en el constructor!)

No hay problema aquí.

@caesay Estoy totalmente de acuerdo en que si no hay restricciones, la asignación no tiene sentido. Pero el siguiente código aún genera errores de compilación, aunque el compilador tiene toda la información necesaria para verificar que el código es correcto.

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>;
    }
}

errores

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

Primero. Sus accesorios en base en el constructor no están escritos. Por lo tanto props.baseProp es any , ¡que no es asignable!

En segundo lugar, sus accesorios en Derived tienen el mismo problema Y le faltan baseState . Lo cual, por supuesto, no funcionará, independientemente de Readonly

TProps extends BaseProps lo que significa que TProps tiene al menos los mismos miembros que tiene BaseProps . Entonces, ¿cómo no se define eso? Entiendo que es posible que el compilador no pueda inferirlo, pero decir que no está definido no parece ser correcto. El mismo pensamiento se puede aplicar a Derived .

@caesay setState en el constructor no es una solución confiable porque este método es asíncrono y aún puede llegar a render sin establecer el estado inicial.

La única solución confiable que puedo ver es establecer todo el estado en las clases derivadas. Esto tiene un inconveniente obvio que:

  1. Esto debe duplicarse en cada clase derivada.
  2. Las clases derivadas necesitan saber sobre el estado que no les importa.

El ejemplo que mostré anteriormente funcionaría en C#, por lo que sería bueno si pudiera funcionar en TypeScript.

  1. ~setState es seguro en el constructor~
  2. En el caso de una clase derivada, el mejor caso que puedo ver es llamar a setState en su componentWillMount . Su base no sabe lo que debería estar en el estado para su hijo, por lo que posiblemente no pueda obtener this.state en una configuración segura. Sin embargo, su subclase puede llamar al componentWillMount del padre y luego establecer cualquier estado que crea que también necesita.
  3. Hay características de lenguaje en muchos idiomas que sería bueno tener en mecanografiado. Algunos son factibles. Otros no lo son. De cualquier manera, no es un argumento para su inclusión.
  4. Los errores que estás viendo tienen sentido. No sugieren un error en el mecanografiado ni en las mecanografías. En cada caso, literalmente está tratando de asignar this.state con un objeto que no coincide con el tipo esperado.

EDITADO, para reflejar que estaba equivocado sobre setState en el constructor y para agregar acentos graves para facilitar la lectura.

@ericanderson No creo que estemos progresando aquí. Te mostré un ejemplo y te agradecería que nos concentráramos en él. De lo contrario, es difícil tener una discusión.

Re setState no es seguro usarlo en el constructor. No arroja un error, pero no establecerá el estado antes de que ocurra el procesamiento. Tengo un código que se rompe debido a eso y los documentos de React son muy claros de que no se deben usar allí.

@pawelpabich No, este no es el lugar para tener este argumento. Estás fundamentalmente equivocado en tu comprensión del idioma. En el ejemplo que proporcionó, no ha satisfecho el contrato "Estado" en NINGUNA de sus asignaciones al estado.

Por ejemplo, cuando haces

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

El estado es exactamente { baseState: props.baseProp } y esto NO cumple con el requisito de TProps extends BaseProps (¡porque no sabemos qué es TProps! Podría tener alguna propiedad).

Después de eso, estás haciendo una tarea _ SEPARADA _.

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

el estado ahora es exactamente { derivedState: props.derivedProp } (¡ha sobrescrito su asignación de estado base!) y esto no satisface DerivedState O BaseProps.

Estás totalmente equivocado al pensar que esto debería funcionar. Si tiene un problema con el funcionamiento de la asignación de variables básicas, háblelo con los diseñadores de idiomas en un nuevo número y déjese caer allí para que dejemos de recibir notificaciones aquí, por favor.

Como nota al margen: TAMBIÉN está anulando su método base render() , lo que significa que su componente base no podrá representar nada. Si está convencido de que esto es lo que desea, puede agregar un miembro protegido getBaseState() y llamarlo desde el constructor derivado cuando establezca el estado (para que no tenga que duplicar la lógica del estado base). Pero lo que creo que realmente quieres es no usar componentes derivados en absoluto. Intente reestructurar para usar la composición (donde tiene un objeto que contiene varios objetos secundarios). Creo que encontrará que resultará mucho más limpio.

Casi no quiero alejarme de la lectura para crear un nuevo proyecto solo para debatir esto contigo, pero, por desgracia...

Estaré corregido sobre setState () en el constructor, pero eso no cambia cómo me siento al usarlo en componentWillMount .

Ejemplo de trabajo de cómo se haría esto:
https://github.com/ericanderson/establecer-estado-ejemplo

Específicamente, 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 si desea implementar un componente polimórfico con un estado inicial, deberá hacer que su componente base sea abstracto y crear una función abstracta getInitialState() (o con un tema similar) para implementar en su clase derivada. Solo desea asignar el estado una vez, ya sea en el constructor o con setState como ha mostrado @ericanderson .

a continuación se muestra su ejemplo convertido en una solución completamente polimórfica, con una separación completa de las preocupaciones con respecto a la construcción del 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 gracias!

@caesay , admito que me equivoqué y, por alguna razón, no vi que las tareas se anulan entre sí. Dicho esto, el uso de MAYÚSCULAS y ! no me ayudó a salir de mi agujero.

@patsissons y @ericanderson se enfocaron en el problema y ahora tenemos una solución que otros pueden usar.

@pawelpabich Estoy de acuerdo en que mis gestos no fueron tan profesionales, pero comprensiblemente, considerando que te di varias explicaciones, muestras, etc., y eliges no escucharme.

entonces solo estaría sobrescribiendo el estado establecido por el padre.

[_si desea_] manejar el estado en su componente base, puede pasar el estado del componente derivado al constructor del componente base

[_si desea manejar el estado en su componente derivado_] puede agregar un miembro protegido getBaseState() y llamarlo desde el constructor derivado cuando establezca el estado.

Lo que hizo @patsissons fue tomar los comentarios ya mencionados aquí y proporcionar un ejemplo de código, que no debería haber sido necesario. Esto no es un desbordamiento de pila, y tampoco proporcionamos muestras de código listas para usar.

Soy nuevo en reaccionar y mecanografiar, tal vez no sepa algo, pero aunque la aplicación se compila sin errores, advertencias ni sugerencias, aparece un error de tiempo de ejecución. A continuación se muestra un componente de ejemplo. Atribuyo el error al estado Readonly . Si la aplicación funcionó antes del cambio de Readonly , luego de este cambio dejó de funcionar y no da errores de tiempo de compilación.

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>
      );
  }
}

El error:

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 (

El estado siempre debe ser un objeto con clave simple afaik, por lo tanto, defina el estado
como algo como: { values: Map <string, string> } y leer
this.state.values.get('aKey')

Op vr 29 sep. 2017 a las 09:01 schreef Janusz Białobrzewski <
[email protected]>:

Soy nuevo en reaccionar y mecanografiar, tal vez no sepa algo, pero incluso
aunque la aplicación se compila sin errores, advertencias ni sugerencias, obtengo un tiempo de ejecución
error. A continuación se muestra un componente de ejemplo. Atribuyo el error a Readonly
estado. Si la aplicación funcionó antes del cambio de solo lectura, luego de esto
cambiarlo dejó de funcionar y no da errores de tiempo de compilación.

importar * como Reaccionar desde 'reaccionar';
exportar clase predeterminada HomePage extiende React.Component> {

componente públicoMontará() {
const mapa = nuevo mapa();
map.set('unaClave', 'unValor');
this.setState(mapa);
}

representación pública() {

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

}
}

El error:

página principal. tsx:12 TypeError no detectado: this.state.get no es una función
en HomePage.render (homePage.tsx:12)
en evaluación (ReactCompositeComponent.js:793)
en medidaLifeCyclePerf (ReactCompositeComponent.js:73)
en ReactCompositeComponentWrapper._renderValidatedComponentWithoutOwnerOrContext (


Estás recibiendo esto porque te mencionaron.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/DefinitelyTyped/DefinitelyTyped/issues/14250#issuecomment-333047367 ,
o silenciar el hilo
https://github.com/notifications/unsubscribe-auth/ABvGhM5hDyRNyUeZuIiGeTZk1N-rfuA4ks5snJW5gaJpZM4LuDWV
.

Gracias, pero parece ser un esfuerzo inútil declarar el estado como Readonly<S> , ya que sus miembros anidados no se ven afectados por Readonly.

Es posible que algún día Readonly se aplique recursivamente, pero por ahora, depende de usted asegurarse de que lo haya manejado correctamente. En su caso, realmente debería declarar ReadonlyMap o

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

o anidado:

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

Podemos usarlo solo para lectura 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;
¿Fue útil esta página
0 / 5 - 0 calificaciones