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

Aberta
#710 3 comentários 5 reações 0 responsáveis Ver no GitHub

Mantenedores costumam responder em até 4 dias

Ninguém assumiu esta issue ainda.

Avaliação

Dificuldade
3/5
Tempo estimado
1-2 dias
Facilidade para iniciantes
48/100
Tipo de issue
Bug
Clareza
Razoavelmente clara
Status de atividade
Estagnada
Stack de tecnologia
javascript, typescript

Direção de pesquisa

Comece localizando as definições de tipo de Draft e WritableDraft e compare como elas lidam com propriedades de símbolos conhecidos. Use o repro em TypeScript da issue para verificar tanto o acesso a propriedades quanto a passagem de um draft para withFoo; estará concluído quando o repro não produzir erros de TS sem alterar o comportamento de mutação pretendido.

Escrita pelo modelo de indexação a partir do texto da issue.

Descrição

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)
Linguagem predominante
JavaScript
Estrelas
29k
Forks
905
Merge médio
3d 16h
PRs com merge (30d)
22

Preparar o ambiente

Este projeto não oferece contêiner de desenvolvimento, Dockerfile nem guia de contribuição, então a configuração fica por sua conta: comece pelo README e veja nosso guia da primeira contribuição para os passos gerais.

Primeiros passos

  1. Leia a issue inteira e depois o guia de contribuição do projeto.
  2. Comente na issue dizendo que vai assumir — evita que duas pessoas façam o mesmo trabalho.
  3. Faça um fork do repositório e trabalhe em uma branch.
  4. Abra um pull request que referencie o número da issue.

Mais de immerjs/immer

Todas as issues de immerjs/immer

Issues semelhantes

Mais issues de JavaScript

Receba novas issues na sua caixa de entrada

Um resumo curto de issues do GitHub para quem está começando.