Operator spread menghapus definisi tipe di typescript


Saya menemukan fenomena aneh ini dalam TypeScript. Ketika menggunakan operator spread, pemeriksaan tipe tampaknya hilang. Saya akan mengharapkan ini menimbulkan kesalahan:

interface Input {
  thingOne: string;
  thingTwo: number;
  thingThree: string;
  thingFour: boolean;
  thingFive: Array<number>
}

interface Output {
  thingThree: string;
  thingFour: boolean;
  thingFive: Array<number>
}

const transformFunction = (input: Input): Output => {
  const result: Output = {
    ...input,
    thingFour: !input.thingFour
  }
  return result
}

Contoh playground Typescript

Saya sedang mengetik result sebagai Output, tetapi menyebarkan objek dari tipe Input ke dalamnya jelas akan menghasilkan hasil yang bukan dari tipe Output. Mengapa TypeScript tidak menangkap ini?

Jawaban #1

Yang kami harapkan di sini adalah untuk memicu fitur Excess Property Check dari TypeScript. Fitur ini memberitahu kita bahwa TypeScript akan memperingatkan kita jika ada properti tambahan dalam objek jika kita secara eksplisit menyebutkan tipe objek. Sayangnya, ini hanya bekerja untuk literal objek.

Sebagai contoh ini:

const transformFunction = (input: Input): Output => {
  return {
    thingOne: "string;",
    thingTwo: 123,
    thingThree: "string;",
    thingFour: !input.thingFour,
    thingFive: [1, 23],
  };
};

Peringatan :

Type '{ thingOne: string; thingTwo: number; thingThree: string; thingFour: boolean; thingFive: number[]; }' is not assignable to type 'Output'.
  Object literal may only specify known properties, and 'thingOne' does not exist in type 'Output'.

Sepertinya kasus operator spread tidak tercakup dalam pemeriksaan properti exces. Lihat di sini: https://github.com/microsoft/TypeScript/issues/41237

Ini adalah pemeriksaan properti berlebih. Menurut @RyanCavanaugh, ini lebih seperti linter, bukan benar-benar bagian dari sistem tipe. Tetapi tidak setiap kasus tercakup oleh pemeriksaan ini, seperti yang Anda perhatikan.

Mereka juga menyebutkan untuk meninjau konversi yang sedang berlangsung pada tipe-tipe yang tepat di sini: https://github.com/microsoft/TypeScript/issues/12936

Jawaban #2

Fungsi ini benar secara tipe karena tipe Input dapat ditugaskan ke tipe Output tanpa masalah, meskipun memiliki properti tambahan. Untuk objek literal saja, ada pemeriksaan properti berlebih, karena properti berlebih dalam objek literal sangat mungkin merupakan kesalahan. Pertimbangkan konstanta ini sebagai contoh.

const o: {a: number} = {a: 1, b: 2}

Karena o sekarang memiliki tipe {a: number}, tidak ada cara bertipe untuk mengakses properti b, jadi TypeScript menganggapnya sebagai kesalahan.

Artikel terkait