Typescript: Saran: Tipe primitif `objek`

Dibuat pada 26 Jan 2015  ·  17Komentar  ·  Sumber: microsoft/TypeScript

Tipe primitif object

Proposal ini menjelaskan tipe primitif baru untuk skrip ketikan object .

Kasus penggunaan

Api inti JavaScript berisi beberapa fungsi yang menggunakan object sebagai parameter:

  • Object.getPrototypeOf
  • Object.getOwnPropertyDescriptor
  • Object.create
  • ... dll

Saat ini tidak ada cara dalam skrip ketikan untuk mencegah penerusan tipe primitif lainnya ( string , number , dll ...) ke fungsi tersebut.
Misalnya Object.create('string') adalah pernyataan ketikan yang benar-benar valid, bahkan jika itu akan berakhir dengan kesalahan.
Membuat tipe primitif object akan memungkinkan untuk memodelkan tanda tangan fungsi tersebut dengan lebih tepat, dan setiap fungsi yang memiliki batasan serupa.

Ketik Memeriksa

Penugasan

Jenis object setara dengan {} dikurangi penetapan jenis dasar lainnya, yang berarti bahwa:

  • tipe dasar lainnya tidak dapat ditetapkan ke object
  • tipe non-dasar apa pun dapat ditetapkan ke object
  • objek hanya dapat ditetapkan ke {} dan any

Perilaku ini koheran dengan cara kerja javascript, tipe mewakili setiap nilai yang menghormati batasan typeof value === 'object' plus undefined .

Ketik penjaga

Penjaga tipe baru harus diperkenalkan seharga object : typeof value === 'object' .
Secara opsional, kompilator juga dapat menerima perbandingan dengan fungsi Object cast: Object(value) === value .

Suggestion help wanted

Komentar yang paling membantu

+1 pada proposal ini. Saya tidak akan menganggap WeakMap sebagai API "ahli", tetapi saya menganggapnya sebagai alasan yang cukup untuk mengimplementasikan ini. Karena runtime membuat perbedaan antara tipe objek dan tipe primitif, masuk akal untuk memiliki fasilitas di TypeScript untuk membuat perbedaan juga.

Proposal ini juga akan memecahkan masalah pengetikan "tas objek" di mana setiap properti bersifat opsional, tetapi jenis primitif lainnya harus dilarang.

Semua 17 komentar

Akan berguna untuk membuat daftar beberapa API selain fungsi Object. yang akan mendapatkan keuntungan dari ini.

Dalam api inti javascript kecuali dari Object hanya mungkin beberapa konstruksi es6 akan mendapatkan keuntungan dari ini (WeakMap, Proxy dll).
Tetapi misalnya setiap fungsi koleksi garis bawah juga akan mendapatkan pengetikan yang lebih baik, kerangka kerja seperti React menggunakan metode 'setState' yang hanya menerima objek atau null , ImmutableJS, Mori dll.

Edit: koleksi garis bawah bekerja dengan semua jenis

Dibahas pada pertemuan tinjauan saran. Ini semua masuk akal, tetapi kita perlu menjustifikasi kompleksitas tipe primitif baru dengan jumlah kesalahan / kekayaan deskripsi yang dapat diberikannya. Pada dasarnya, lebih banyak contoh API yang tidak dapat beroperasi pada primitif, terutama yang bukan API "ahli" (mis. Proxy)

Posting lebih banyak sebagai referensi daripada rekomendasi: wink:

interface String { _primitiveBrand?: string; }
interface Boolean { _primitiveBrand?: boolean; }
interface Number { _primitiveBrand?: number; }

interface ObjectOnly {  _primitiveBrand?: void; }

function fn(x: ObjectOnly) { }

// Error
fn(43);
// Error
fn('foo');
// OK
fn({});
// OK
fn(window);

+1 pada proposal ini. Saya tidak akan menganggap WeakMap sebagai API "ahli", tetapi saya menganggapnya sebagai alasan yang cukup untuk mengimplementasikan ini. Karena runtime membuat perbedaan antara tipe objek dan tipe primitif, masuk akal untuk memiliki fasilitas di TypeScript untuk membuat perbedaan juga.

Proposal ini juga akan memecahkan masalah pengetikan "tas objek" di mana setiap properti bersifat opsional, tetapi jenis primitif lainnya harus dilarang.

Object.observe membutuhkan target non-primitif juga: http://arv.github.io/ecmascript-object-observe/#Object.observe

Saya rasa judulnya agak membingungkan karena menyebutkan kata "primitif". Ini juga bisa disebut _ "Jenis objek ECMAScript" _ atau _ "Jenis objek waktu proses" _. Yang akan dapat ditetapkan dari apa pun selain tipe primitif (termasuk undefined tipe dan simbol), fungsi atau tipe konstruktor. Kriteria untuk jenis object legal harus didasarkan pada penjaga berikut:

let isObject (x) => typeof x === "object";

Menurut MDN , ini adalah keluaran dari typeof :

Belum ditentukan: "tidak ditentukan"
Null : "object" (lihat di bawah)
Boolean : "boolean"
Nomor : "number"
String : "string"
Simbol (baru di ECMAScript 2015) : "simbol"
Objek host (disediakan oleh lingkungan JS) : Tergantung pada implementasi
Objek fungsi (mengimplementasikan [[Call]] dalam istilah ECMA-262) : "function"
Objek lainnya : "object"

Tanpa tipe ini, tidak ada cara untuk mencocokkan tipe tepat dengan tepat untuk penjaga yang disebutkan di atas, bahkan sebagai penjaga yang ditentukan pengguna. Ini juga penting untuk digunakan dengan fungsi apa pun yang benar-benar membutuhkan objek yang memiliki properti dan memungkinkan for in loop dan panggilan ke prototipe Object , dan untuk mengimplementasikan batasan umum seperti T extends object dan kemudian mereferensikan properti atau menggunakan fungsi prototipe dengan aman.

Namun, memiliki fungsi dan konstruktor yang dikecualikan akan menjadi sedikit membatasi dalam beberapa kasus, jadi mungkin ada tipe lain yang akan menyertakannya juga dan disebut _ "tipe objek non-primitif" _. Solusi parsial dapat berupa gabungan object | Function meskipun pemeran atau penjaga tambahan diperlukan untuk menanganinya dengan benar.

Menerima PR. Ini tampaknya menjadi masalah umum; ini akan menjadi perubahan besar bagi siapa pun yang cukup berani untuk menulis interface object { ... } . Penerapannya harus langsung dan mengikuti aturan yang diuraikan di atas.

Catatan tambahan: Kami semua bertanya-tanya di mana @fdecampredon berada!

@RyanCavanaugh Pindah kota kerja, dan sayangnya tidak banyak ketikan di pekerjaan baru saya: D

Bagus. Saya ingin menggunakan tipe ini di TS1.8.

Saya juga ingin melihat sesuatu seperti tipe object . Namun, saya mempertanyakan apakah itu harus sesuai dengan typeof value === 'object' , karena ini akan mengecualikan fungsi. Alih-alih, menurut saya tipe prospektif object harus mencerminkan tipe bahasa Object, yang menyertakan fungsi. Ada beberapa alasan untuk ini:

  • API yang selalu menerima objek biasa, sejauh yang saya tahu, juga menerima fungsi.
  • Fungsi mewarisi dari konstruktor Object .

Saya akan mengambil ini secara berurutan.

Lebah

API seperti WeakMap yang hanya menerima objek menerima tipe bahasa Objek, bukan hanya objek biasa. Berikut ini tidak masalah:

function theAnswer() {}

let map = new WeakMap();

map.set(theAnswer, 42);
console.log(map.get(theAnswer)); // 42

Ini berlaku untuk API khusus seperti untuk API bawaan. Jika saya mengharapkan sebuah objek, saya biasanya hanya menginginkan sekumpulan properti. Fungsi hanyalah kumpulan properti yang dapat dipanggil.

Warisan

Karena Function memperluas konstruktor Object , kita dapat menggunakan metode statis dan contoh yang tersedia pada Object pada fungsi juga. Misalnya, berikut ini mungkin:

class DeepThought {
  static getAnswer() {
    return 42;
  }
}

let computer = Object.create(DeepThought);

console.log(computer.getAnswer()); // 42
console.log(Object.getPrototypeOf(computer)); // [Function: DeepThought]

Meskipun contoh di atas agak konyol, ini hanya menggambarkan bahwa API yang menggunakan metode Object internal juga dapat menerima fungsi.

Jadi saya akan menyarankan bahwa tipe object sesuai dengan yang berikut, yang sesuai dengan tipe bahasa Objek (kecuali bahwa itu termasuk null , tetapi tidak ada perlindungan terhadap null dalam TypeScript dalam hal apapun).

function isObject(value) {
  return typeof value === 'object' || typeof value === 'function';
}

Kasus Penggunaan

Saya memiliki proyek bernama Deep Map yang berulang melalui pasangan nilai kunci dari objek bersarang dan mengubah nilai primitif di sepanjang jalan. Dengan demikian, ini membedakan antara tipe primitif dan non-primitif. Saya harus menentukan antarmuka khusus NonPrimitive , sebagai berikut:

interface NonPrimitive {
  [key: string]: any;
  [index: number]: any;
}

export class DeepMap {
  // ...
  private mapObject(obj: NonPrimitive): NonPrimitive { /* ... */ }
}

Ini bukan pertama kalinya saya harus mendefinisikan antarmuka NonPrimitive . Alangkah baiknya jika saya bisa melakukan ini:

export class DeepMap {
  // ...
  private mapObject(obj: object): object { /* ... */ }
}

Seperti yang saya sarankan di atas, saya tidak terlalu peduli apakah parameter obj dapat dipanggil atau tidak. Yang penting adalah bahwa ini adalah dari Object _language type_, yaitu, bahwa itu adalah bundel properti yang pasangan key-value-nya dapat saya lakukan iterasi.

Saya setuju bahwa fungsinya adalah object s. Tujuannya adalah untuk mengecualikan primitif.

Oke, saya pikir itu pasti niatnya. Saya hanya berpikir mungkin saya melewatkan sesuatu dengan semua pembicaraan tentang typeof value === 'object' .

apakah object type ini memungkinkan penetapan properti ad-hoc (seperti any )? Sebagai contoh:

const foo: object = {};

foo.bar = 'baz';

Tidak

Apa perbedaan praktis antara

export class DeepMap {
  // ...
  private mapObject(obj: object): object { /* ... */ }
}

dan

export class DeepMap {
  // ...
  private mapObject(obj: Object): Object { /* ... */ }
}

? (Menggunakan object vs Object ). Menurut saya, Function berasal dari Object , jadi saya tidak mengerti mengapa kita belum bisa melakukannya. Bisakah Anda menjelaskan?

@trusktr Semua nilai selain null dan undefined dapat dialihkan ke tipe Object ; fungsi yang menerima Object akan mengambil string, angka, boolean, atau simbol. Hanya nilai non-primitif yang dapat ditetapkan ke object ; melewatkan string, dll, akan menghasilkan kesalahan waktu kompilasi. Tipe object berguna ketika kita mengharapkan nilai non-primitif, tetapi kita tidak peduli apa propertinya.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat

Masalah terkait

manekinekko picture manekinekko  ·  3Komentar

CyrusNajmabadi picture CyrusNajmabadi  ·  3Komentar

blendsdk picture blendsdk  ·  3Komentar

Antony-Jones picture Antony-Jones  ·  3Komentar

fwanicka picture fwanicka  ·  3Komentar