Ketikkan definisi dalam objek literal dalam TypeScript

346

Di kelas-kelas TypeScript dimungkinkan untuk mendeklarasikan tipe untuk properti, misalnya:

class className {
  property: string;
};

Bagaimana cara mendeklarasikan tipe properti dalam objek literal?

Saya sudah mencoba kode berikut tetapi tidak dikompilasi:

var obj = {
  property: string;
};

Saya mendapatkan kesalahan berikut:

Nama 'string' tidak ada dalam cakupan saat ini

Apakah saya melakukan sesuatu yang salah atau ini bug?

Dace Zarina
sumber

Jawaban:

424

Anda cukup dekat, Anda hanya perlu mengganti =dengan a :. Anda dapat menggunakan tipe objek literal (lihat bagian spesifikasi 3.5.3) atau antarmuka. Menggunakan tipe objek literal dekat dengan apa yang Anda miliki:

var obj: { property: string; } = { property: "foo" };

Tapi Anda juga bisa menggunakan antarmuka

interface MyObjLayout {
    property: string;
}

var obj: MyObjLayout = { property: "foo" };
Brian Terlson
sumber
14
Opsi KERING (Jangan Ulangi Diri Sendiri) oleh @Rick Love dengan para operator tampaknya jauh lebih rapi. Hanya berkomentar, bukan downvoting ...
spechter
Saya tahu ini telah dijawab beberapa waktu lalu, tetapi apakah saya salah dalam asumsi bahwa masalah dapat muncul ketika kelas memiliki metode serta properti? Karena kelas tidak diinisialisasi dan kami hanya menetapkan properti, memanggil metode pada kelas akan menyebabkan pengecualian nol. Pada dasarnya, objek yang kita buat hanya 'bertindak' sebagai kelas karena kita menetapkan tipenya, tetapi sebenarnya bukan turunan dari kelas itu. Yaitu kita perlu membuat kelas dengan kata kunci 'baru'. Dan kita kemudian kembali ke titik 1, karena kita tidak dapat melakukan sesuatu seperti kelas baru () {prop: 1}; di TS seperti yang kita dapat di C #, misalnya.
DeuxAlpha
@DeuxAlpha Ini ditugaskan untuk antarmuka , yang tidak dapat memiliki metode. Saya tidak percaya bahwa Anda dapat menugaskan ke kelas seperti ini.
Mog0
tautan ke spec akan menyenangkan :)
ahong
@DeuxAlpha ini membuat objek literal, bukan objek kelas. Juga sebuah antarmuka dapat memiliki metode. Jika antarmuka Anda mendefinisikan metode, maka objek literal juga harus mendefinisikannya - itu tidak akan nol. Objek literal harus memenuhi semua yang didefinisikan antarmuka atau sistem tipe akan menunjukkan kesalahan.
Rick Love
291

Pembaruan 2019-05-15 (Pola Kode Peningkatan sebagai Alternatif)

Setelah bertahun-tahun menggunakan constdan mendapatkan manfaat dari kode yang lebih fungsional, saya akan merekomendasikan untuk tidak menggunakan di bawah ini dalam banyak kasus. (Saat membangun objek, memaksa sistem tipe ke dalam tipe tertentu alih-alih membiarkannya menyimpulkan tipe sering merupakan indikasi bahwa ada sesuatu yang salah).

Sebagai gantinya saya akan merekomendasikan menggunakan constvariabel sebanyak mungkin dan kemudian menyusun objek sebagai langkah terakhir:

const id = GetId();
const hasStarted = true;
...
const hasFinished = false;
...
return {hasStarted, hasFinished, id};
  • Ini dengan benar akan mengetik semuanya tanpa perlu mengetik secara eksplisit.
  • Tidak perlu mengetik ulang nama bidang.
  • Ini mengarah ke kode terbersih dari pengalaman saya.
  • Ini memungkinkan kompiler untuk memberikan lebih banyak verifikasi status (misalnya, jika Anda kembali di beberapa lokasi, kompiler akan memastikan jenis objek yang sama selalu dikembalikan - yang mendorong Anda untuk mendeklarasikan seluruh nilai pengembalian di setiap posisi - memberikan penjelasan yang sangat jelas niat nilai itu).

Penambahan 2020-02-26

Jika Anda benar-benar membutuhkan jenis yang Anda dapat diinisialisasi dengan malas: Tandai itu adalah jenis gabungan yang dapat dibatalkan (nol atau Jenis). Sistem tipe akan mencegah Anda menggunakannya tanpa terlebih dahulu memastikan memiliki nilai.

Di tsconfig.json, pastikan Anda mengaktifkan pemeriksaan nol yang ketat:

"strictNullChecks": true

Kemudian gunakan pola ini dan izinkan sistem tipe untuk melindungi Anda dari akses null / undefined yang tidak disengaja:



const state = {
    instance: null as null | ApiService,
    // OR
    // instance: undefined as undefined | ApiService,

};

const useApi = () => {
    // If I try to use it here, the type system requires a safe way to access it

    // Simple lazy-initialization 
    const api = state?.instance ?? (state.instance = new ApiService());
    api.fun();

    // Also here are some ways to only access it if it has value:

    // The 'right' way: Typescript 3.7 required
    state.instance?.fun();

    // Or the old way: If you are stuck before Typescript 3.7
    state.instance && state.instance.fun();

    // Or the long winded way because the above just feels weird
    if (state.instance) { state.instance.fun(); }

    // Or the I came from C and can't check for nulls like they are booleans way
    if (state.instance != null) { state.instance.fun(); }

    // Or the I came from C and can't check for nulls like they are booleans 
    // AND I was told to always use triple === in javascript even with null checks way
    if (state.instance !== null && state.instance !== undefined) { state.instance.fun(); }
};

class ApiService {
    fun() {
        // Do something useful here
    }
}

Jangan lakukan hal di bawah ini dalam 99% kasus:

Pembaruan 2016-02-10 - Untuk Menangani TSX (Terima Kasih @Josh)

Gunakan asoperator untuk TSX.

var obj = {
    property: null as string
};

Contoh yang lebih panjang:

var call = {
    hasStarted: null as boolean,
    hasFinished: null as boolean,
    id: null as number,
};

Jawaban Asli

Gunakan operator transmisi untuk membuat ringkas ini (dengan memberikan null ke jenis yang diinginkan).

var obj = {
    property: <string> null
};

Contoh yang lebih panjang:

var call = {
    hasStarted: <boolean> null,
    hasFinished: <boolean> null,
    id: <number> null,
};

Ini jauh lebih baik daripada memiliki dua bagian (satu untuk mendeklarasikan tipe, yang kedua untuk menyatakan default):

var callVerbose: {
    hasStarted: boolean;
    hasFinished: boolean;
    id: number;
} = {
    hasStarted: null,
    hasFinished: null,
    id: null,
};
Rick Love
sumber
10
Jika Anda menggunakan TSX (TS dengan JSX), Anda tidak dapat menggunakan penamaan braket sudut, sehingga garis-garis itu menjadi seperti di property: null as stringmana perbedaan penting adalah asoperator.
Josh
2
@RickLove Apakah ini sebenarnya membatasi jenis variabel objek, atau apakah ini hanya cara untuk menentukan jenis ketika ditugaskan? Dengan kata lain, setelah Anda menetapkan variabel calldalam contoh kedua Anda, dapatkah Anda menetapkan jenis yang sama sekali berbeda untuk itu?
Daniel Griscom
3
Ini seharusnya menjadi jawaban
Drew R
4
tidak bekerja Error:(33, 15) TS2352:Type 'null' cannot be converted to type 'string'.
slideshowp2
2
Apakah ini hanya penyalahgunaan fitur bahasa atau apakah ini sebenarnya sah? Bisakah Anda memberikan tautan untuk membaca mor ke dokumen resmi? Terima kasih!
Qwerty
31

Saya terkejut bahwa tidak ada yang menyebutkan ini tetapi Anda hanya bisa membuat antarmuka yang disebut ObjectLiteral, yang menerima key: valuepasangan jenis string: any:

interface ObjectLiteral {
  [key: string]: any;
}

Maka Anda akan menggunakannya, seperti ini:

let data: ObjectLiteral = {
  hello: "world",
  goodbye: 1,
  // ...
};

Bonus tambahan adalah Anda dapat menggunakan kembali antarmuka ini berkali-kali sesuai kebutuhan, pada banyak objek yang Anda inginkan.

Semoga berhasil.

LogicalBranch
sumber
3
Ini adalah ide yang buruk, itu membuat sistem tipe tidak berharga. Maksud naskah adalah untuk memungkinkan sistem tipe membantu mencegah kesalahan dan juga untuk membantu menyediakan fungsionalitas autocomplete yang lebih baik dalam perkakas - ini pada dasarnya menonaktifkan semua manfaat dari Typecript. Akan lebih baik untuk tidak menggunakan antarmuka apa pun dalam contoh di atas.
Rick Love
1
@ RickLove Saya sangat tidak setuju. Ini sangat berguna ketika beberapa properti bersifat opsional tetapi kami masih ingin mendefinisikan dengan jelas semua tipe di dalamnya (misalnya berisi argumen untuk suatu fungsi). Ini hanya dapat dilihat sebagai gula sintaksis dan secara harfiah berfungsi seperti operator penyebaran untuk properti Antarmuka .
CPHPython
@ CPHPython mengapa tidak hanya menentukan parameter opsional dengan tipe spesifiknya? Satu-satunya waktu yang masuk akal adalah jika nama tidak dikenal pada waktu kode (yaitu mereka berasal dari database atau sumber eksternal). Juga untuk kombinasi argumen yang kompleks, jenis-jenis serikat berfungsi dengan baik. Jika Anda mengkode terhadap nama tertentu, mereka harus didefinisikan jika memungkinkan. Jika hanya data yang tidak mempengaruhi logika, maka tentu saja tinggalkan itu dari sistem tipe.
Rick Love
1
@RickLove "nama-nama tidak dikenal pada waktu kode" -> ini adalah contoh yang baik dan praktis, nilai-nilai dari jenis kunci tersebut diketahui dan semuanya sama (misalnya string ). Pikiran bahwa saya hanya menganjurkan penggunaan [key: string]bagian, bukan bagian apa pun sebagai definisi jenis nilai ... Itu memang akan menghilangkan kegunaan jenis.
CPHPython
1
Bagaimana cara saya jika saya ingin memperbolehkan string dan angka ditambahkan tetapi bukan tipe lainnya?
DonkeyBanana
14

Jika Anda mencoba menulis anotasi jenis, sintaksnya adalah:

var x: { property: string; } = ...;

Jika Anda mencoba menulis objek literal, sintaksnya adalah:

var x = { property: 'hello' };

Kode Anda mencoba menggunakan nama jenis di posisi nilai.

Ryan Cavanaugh
sumber
10
Anda var x: { property: string; } = ...;menggoda! Saya berharap elipsis adalah sintaks yang valid untuk menjadi singkatan var x: { property: string; } = { property: 'hello' };.
Jason Kleban
10

Dalam TypeScript jika kita mendeklarasikan objek maka kita akan menggunakan sintaks berikut:

[access modifier] variable name : { /* structure of object */ }

Sebagai contoh:

private Object:{ Key1: string, Key2: number }
Patel mukund
sumber
7

Jika Anda mencoba menambahkan pengetikan ke objek literal yang dirusak , misalnya dalam argumen ke suatu fungsi, sintaksnya adalah:

function foo({ bar, baz }: { bar: boolean, baz: string }) {
  // ...
}

foo({ bar: true, baz: 'lorem ipsum' });
Egor
sumber
5

Jika properti Anda memiliki tipe yang sama, Anda bisa menggunakan tipe utilitas yang telah ditentukan Record:

type Keys = "property" | "property2"

var obj: Record<Keys, string> = {
  property: "my first prop",
  property2: "my second prop",
};

Tentu saja Anda dapat melangkah lebih jauh dan menentukan jenis khusus untuk nilai properti Anda:

type Keys = "property" | "property2"
type Value = "my prop" | "my other allowed prop"

var obj: Record<Keys, Value> = {
  property: "my prop",
  property2: "my second prop", // TS Error: Type '"my second prop"' is not assignable to type 'Value'.
};
streletss
sumber
2
Apa yang saya butuhkan. Terima kasih! Naskah untuk kemenangan!
Audacitus
Saya juga akan menggunakan letbukan di varsini.
Fwd079
3
// Use ..

const Per = {
  name: 'HAMZA',
  age: 20,
  coords: {
    tele: '09',
    lan: '190'
  },
  setAge(age: Number): void {
    this.age = age;
  },
  getAge(): Number {
    return age;
  }
};
const { age, name }: { age: Number; name: String } = Per;
const {
  coords: { tele, lan }
}: { coords: { tele: String; lan: String } } = Per;

console.log(Per.getAge());
Hamza Ibrahim
sumber
3
Hai dan selamat datang di SO! Dapatkah Anda memperluas jawaban Anda sama sekali, akan sangat membantu untuk menjelaskan bagaimana / mengapa ini bekerja.
pesta-cincin
1

Dalam kode Anda:

var obj = {
  myProp: string;
};

Anda sebenarnya membuat objek literal dan menetapkan string variabel ke properti myProp. Meskipun praktik yang sangat buruk ini sebenarnya akan menjadi kode TS yang valid (jangan gunakan ini!):

var string = 'A string';

var obj = {
  property: string
};

Namun, yang Anda inginkan adalah objek literal diketik. Ini dapat dicapai dengan berbagai cara:

Antarmuka:

interface myObj {
    property: string;
}

var obj: myObj = { property: "My string" };

Jenis kustom:

type myObjType = {
    property: string
};

var obj: myObjType = { property: "My string" };

Operator cor:

var obj = {
    myString: <string> 'hi',
    myNumber: <number> 132,
};

Jenis objek literal:

var obj: { property: string; } = { property: "Mystring" };
Willem van der Veen
sumber