TS errors for draft objects with properties that are indexed using well-known symbols

Abierto
#710 3 comentarios 5 reacciones 0 asignados Ver en GitHub

Los mantenedores suelen responder en 4 días

Nadie ha tomado este issue todavía.

Evaluación

Dificultad
3/5
Tiempo estimado
1-2 días
Aptitud para principiantes
48/100
Tipo de issue
Error
Claridad
Bastante claro
Estado de actividad
Estancado
Stack tecnológico
javascript, typescript

Línea de trabajo

Comienza localizando las definiciones de tipos de Draft y WritableDraft y compara cómo gestionan las propiedades de símbolos conocidos. Usa la reproducción de TypeScript del issue para comprobar tanto el acceso a propiedades como el paso de un draft a withFoo; estará terminado cuando la reproducción no produzca errores de TS sin cambiar el comportamiento de mutación previsto.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

typescript

🐛 Bug Report

Draft<T> objects (at least according to TS) don't bring along any symbol-indexed properties from the original object. Is this expected? I'm not sure if this is only an issue in the TS types, or is the underlying JS draft object also missing its symbol-indexed properties?

Although well-known symbols are usually used with classes, I was able to repro the problem with a plain object too.

I'm using TS 4.1, if it matters.

FWIW, I ran into this because I was trying to call produce() with a deeply-nested object which had a Uint8Array-valued property far down in the tree. When I tried to pass the draft object to another method that expected the original type, TS complained that [Symbol.iterator] and [Symbol.toStringTag] properties that were required on Uint8Array but missing on the Draft<T> object. I'm not trying to mutate the array (that'd be #696); I'm just expecting a deep clone but (at least from TS's perspective) the symbol properties are missing.

Link to repro

import produce, { Draft } from 'immer';

const foo = {
  a() { return 42; },
  get [Symbol.toStringTag]() { return 'foo'; }
}

type Foo = typeof foo;

function withFoo(f: Foo) {
  return f[Symbol.toStringTag];
}

const ok = foo[Symbol.toStringTag];  // no error
const ok2 = withFoo(foo);  // no error

const producer = produce((draft: Draft<Foo>) => {
  draft.a();  // no error
  withFoo(draft);
  /*      ^^^^^
    Argument of type 'WritableDraft<{ a(): number; readonly [Symbol.toStringTag]: string; }>' 
    is not assignable to parameter of type '{ a(): number; readonly [Symbol.toStringTag]: string; }'.
    Property '[Symbol.toStringTag]' is missing in type 'WritableDraft<{ a(): number; 
    readonly [Symbol.toStringTag]: string; }>' but required in type 
    '{ a(): number; readonly [Symbol.toStringTag]: string; }'. (2345)
  */

  const fail = draft[Symbol.toStringTag];
  /*           ^^^^^^^^^^^^^^^^^^^^^^^^^
     Element implicitly has an 'any' type because expression of type 'symbol' can't be used
     to index type 'WritableDraft<{ a(): number; readonly [Symbol.toStringTag]: string; }>'.(7053)
  */
});

https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBGKEAmBXAxgUwDRwN5wAiUAhgGbwC+cZSIcA5KCJlAwNwBQn6EAdgGd4ZCBDgBefJzhwSACgCU+OFEwxUUPnAAsAJnZxK2aXADmauAG0AygE8QAIwgAbAHQwI1mFGB9TAFRJTAF1FZVV1TUYRCA5DTkpuGFswTDgAMVEJOGTUiDIaUS5OMlQ+dBhgfjgAd2AYAAtMiDkyAC4M0SU8EwiNLTIbeyc3Dy8fP0CQrkSefiE4CABrbJihxxd3T29fAKDggzgAeiO4PjFWJCg5wXhl3Wy6xubWrsOTs4uoK+5eW4QkGgsFBsogUBhMHI5MhSBQOsRyDAADzNAB8SnEqKkMhhiNc8gU71O5zgl2gJieTVE0NhMEJJiOACoZCy4AA9DkckwyACCUFMqBYfDuBVyaQYAHUfDASA5nJgERQkQQCR0+IKHKwDKoSMh+M5bFY7BtRtsJnsQh0hOaDJRUQw4Ny4MABJ94CQBAJgKY+LL5TkxGASKQWDBWItRSlxSrFGqNVqVJhdfrDesRltxrspsErTs-LaGK4nQAFJCpWCGhhpzZjPMW4IOl1wEAur1+Z1aMWMKX1P0K2nK2Sxs7xqAGJ06vV8A1G4Y1s1Z-a5m2Ge1wByoeCqACOqGAqmQHZyUcdrIYMYUcccCcnKdnJozdezy92BdccDkugAzNoAKwKExGSObgZD+BYyBIYBnGyXEKGrU1M0mfYuBkJlWXQmROSw7CcNwp04AAUXlIV4FAMBnGAdB6hnBoPVkLQGBIPhbAdLtNXQEhUAENJMAAD0QTBPSqLR8mPVJGAEOdnAdDi+AYeBNTgLjMGQfCPA7ZA+LE8UexlOV+0RQdVRHa8x0TZNp1TY101rc1nzga1X1XQs5AAdgABl-L8AJkICEnpIA

LMK if you want me to turn the TS playground code above into a CodeSandbox example; happy to do so.

To Reproduce

Steps to reproduce the behavior:

  1. Create a producer that accepts a TS type that has a well-known symbol property
  2. Try to read that property or call a function that accepts a parameter of T from Draft<T>. Note that mutation is not required-- this problem affects read-only access.

Observed behavior

TS errors as noted above.

Expected behavior

No TS errors.

Environment

We only accept bug reports against the latest Immer version.

  • Immer version:
  • I filed this report against the latest version of Immer
  • [n/a (TS only)] Occurs with setUseProxies(true)
  • [n/a (TS only)] Occurs with setUseProxies(false) (ES5 only)
Lenguaje dominante
JavaScript
Estrellas
29k
Forks
905
Merge medio
3 d 16 h
PR fusionados (30 d)
22

Preparar el entorno

Este proyecto no incluye contenedor de desarrollo, Dockerfile ni guía de contribución, así que la configuración corre por tu cuenta: empieza por su README y consulta nuestra guía para la primera contribución para los pasos generales.

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de immerjs/immer

Todos los issues de immerjs/immer

Issues similares

Más issues de JavaScript

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.