javascript - Typescript: menandai properti objek sebagai non-enumerable?


Saya menggunakan pengetikan/branding nominal untuk merepresentasikan nilai yang telah melewati useMemo React.

type Memoed<T> = T extends Primitive ? T
  : T extends { __MEMOED: true } ? T
  : T & { __MEMOED: true };

declare function useMemo<T extends any>(
  callback: () => T,
  deps: ReadonlyArray<Primitive | Memoed<object>>,
): Memoed<T>;

Ini bekerja dengan baik sebagian besar waktu. Namun, ini menyebabkan masalah ketika saya menggunakan Object.keys, Object.values, atau saat saya menyebarkan objek. Misalnya, jika saya menyebarkan objek yang sudah di-memo untuk membuat objek baru, objek baru tersebut tidak di-memo. Namun, itu masih akan memiliki properti __IS_USE_MEMO, sehingga Typescript akan mengizinkannya sebagai argumen untuk useMemo. Misalnya:

const objA = useMemo(() => ({ a: 1 }), []);
const objB = { ...objA };
const objC = useMemo(() => objB, [objB]); // Should be error

Playground TS

Jika saya bisa menandai __MEMOED sebagai tidak dapat dienumerasi, maka masalah ini seharusnya hilang. Apakah itu mungkin?

Jawaban #1

Sepertinya satu-satunya cara untuk melakukan ini adalah dengan mendefinisikan sebuah kelas dengan tanda "memoed" Anda sebagai metode (secara teknis tidak harus berupa metode, tetapi memperluas prototipe dengan hal lain lebih rumit).

Ini sepertinya benar-benar berhasil (alih-alih definisi Anda untuk __MEMOED):

declare class __MEMOED {
  memoed(): true
}

type Memoed<T> = T extends Primitive ? T
  : T extends __MEMOED ? T
  : T & __MEMOED

Meskipun… jika kamu menandai memo apa pun yang bukan Object dasar, semuanya menjadi sangat aneh dan pada titik itu kamu benar-benar perlu memperluas kelas dasar.