Bagaimana cara mendeklarasikan tipe sebagai nullable dalam TypeScript?

248

Saya memiliki antarmuka dalam TypeScript.

interface Employee{
    id: number;
    name: string;
    salary: number;
}

Saya ingin menjadikan salarysebagai bidang nullable (Seperti yang bisa kita lakukan di C #). Apakah ini mungkin dilakukan dalam TypeScript?

Amitabh
sumber

Jawaban:

276

Semua bidang dalam JavaScript (dan dalam TypeScript) dapat memiliki nilai nullatau undefined.

Anda dapat membuat bidang opsional yang berbeda dari nullable.

interface Employee1 {
    name: string;
    salary: number;
}

var a: Employee1 = { name: 'Bob', salary: 40000 }; // OK
var b: Employee1 = { name: 'Bob' }; // Not OK, you must have 'salary'
var c: Employee1 = { name: 'Bob', salary: undefined }; // OK
var d: Employee1 = { name: null, salary: undefined }; // OK

// OK
class SomeEmployeeA implements Employee1 {
    public name = 'Bob';
    public salary = 40000;
}

// Not OK: Must have 'salary'
class SomeEmployeeB implements Employee1 {
    public name: string;
}

Dibandingkan dengan:

interface Employee2 {
    name: string;
    salary?: number;
}

var a: Employee2 = { name: 'Bob', salary: 40000 }; // OK
var b: Employee2 = { name: 'Bob' }; // OK
var c: Employee2 = { name: 'Bob', salary: undefined }; // OK
var d: Employee2 = { name: null, salary: 'bob' }; // Not OK, salary must be a number

// OK, but doesn't make too much sense
class SomeEmployeeA implements Employee2 {
    public name = 'Bob';
}
Ryan Cavanaugh
sumber
35
Sepertinya jenis yang benar - benar dapat dibatalkan dan cek-kosong yang ketat telah diterapkan dan akan tiba dengan TypeScript 2.0! (atau typescript@nextsekarang.)
mindplay.dk
Anda yakin tentang var c pada contoh pertama? Sepertinya saya bahwa var b dan var c sama di sana.
martinp999
Untuk menetapkan nilai nol atau tidak ditentukan tanpa kesalahan kompilasi, opsi tsconfig "strict" harus dihapus atau sama dengan "false""strict" : false
Nicolas Janel
1
Ini salah. JS membedakan antara nol dan tidak terdefinisi. Kode yang benar seharusnya salary:number|null;Jika Anda melakukannya, salary?:number; salary = null;Anda akan mendapatkan kesalahan. Namun, salary = undefined;akan berfungsi dengan baik dalam kasus ini. Solusi: gunakan Union yaitu '|'
Ankur Nigam
125

Jenis serikat ada dalam pikiran saya pilihan terbaik dalam hal ini:

interface Employee{
   id: number;
   name: string;
   salary: number | null;
}

// Both cases are valid
let employe1: Employee = { id: 1, name: 'John', salary: 100 };
let employe2: Employee = { id: 1, name: 'John', salary: null };

EDIT: Agar ini berfungsi seperti yang diharapkan, Anda harus mengaktifkan strictNullChecksin tsconfig.

bjaksik
sumber
9
Jika Anda menggunakan --strictNullChecks (yang seharusnya), ini adalah solusi yang valid. Saya tidak akan menggunakannya dalam mendukung anggota opsional, karena memaksa Anda untuk menambahkan null eksplisit pada semua objek literal, tetapi untuk nilai-nilai fungsi pengembalian, itu adalah cara untuk pergi.
geon
78

Agar lebih seperti C # , tentukanNullable jenisnya seperti ini:

type Nullable<T> = T | null;

interface Employee{
   id: number;
   name: string;
   salary: Nullable<number>;
}

Bonus:

Untuk membuat Nullableberperilaku seperti tipe skrip bawaan, tentukan dalam global.d.tsfile definisi di folder sumber root. Jalan ini bekerja untuk saya:/src/global.d.ts

Tim Santeford
sumber
1
Jawaban favorit saya - langsung menjawab pertanyaan tanpa membacanya.
Lqueryvg
1
Menggunakan ini memecah penyelesaian otomatis dari objek properti. Sebagai contoh jika kita memiliki emp: Partial<Employee>, kita dapat melakukan emp.idatau emp.namelain - lain tetapi jika kita memiliki emp: Nullable<Employee>, kita tidak dapat melakukannyaemp.id
Yousuf Khan
1
Ini adalah jawaban aktual untuk pertanyaan itu.
Patrick
36

Cukup tambahkan tanda tanya ?ke bidang opsional.

interface Employee{
   id: number;
   name: string;
   salary?: number;
}
Miguel Ventura
sumber
54
Seperti yang ditunjukkan Ryan ...? berarti opsional dalam naskah, tidak dapat dibatalkan. Tanpa? berarti var harus diatur ke nilai termasuk nol atau tidak terdefinisi. Dengan? Anda dapat melewatkan seluruh pernyataan-hal.
He Nrik
3
Terima kasih! I googled untuk "nilai opsional naskah" jadi ini adalah persis apa yang saya cari.
Fellow Stranger
13

Anda bisa menerapkan tipe yang ditentukan pengguna seperti berikut:

type Nullable<T> = T | undefined | null;

var foo: Nullable<number> = 10; // ok
var bar: Nullable<number> = true; // type 'true' is not assignable to type 'Nullable<number>'
var baz: Nullable<number> = null; // ok

var arr1: Nullable<Array<number>> = [1,2]; // ok
var obj: Nullable<Object> = {}; // ok

 // Type 'number[]' is not assignable to type 'string[]'. 
 // Type 'number' is not assignable to type 'string'
var arr2: Nullable<Array<string>> = [1,2];
Willem van der Veen
sumber
10
type MyProps = {
  workoutType: string | null;
};
Ritwik
sumber
4

saya punya pertanyaan yang sama beberapa waktu lalu .. semua jenis di ts dapat dibatalkan, karena void adalah subtipe dari semua jenis (tidak seperti, misalnya, scala).

lihat apakah diagram alur ini membantu - https://github.com/bcherny/language-types-comparison#typescript

bcherny
sumber
2
-1: Ini tidak benar sama sekali. Adapun void'subtipe semua jenis' ( tipe bawah ), lihat utas ini . Juga grafik yang Anda berikan untuk scala juga salah. Nothingdalam scala sebenarnya adalah tipe terbawah. Naskah, atm, tidak memiliki tipe dasar sedangkan scala tidak .
Daniel Shin
2
"Subtipe semua tipe"! = Tipe terbawah. Lihat spesifikasi TS di sini github.com/Microsoft/TypeScript/blob/master/doc/…
bcherny
3

Jenis nullable dapat memanggil kesalahan runtime. Jadi saya pikir itu baik untuk menggunakan opsi kompiler --strictNullChecksdan menyatakan number | nullsebagai tipe. juga dalam kasus fungsi bersarang, meskipun tipe input adalah nol, kompiler tidak dapat mengetahui apa yang bisa rusak, jadi saya sarankan gunakan !(tanda exclamination).

function broken(name: string | null): string {
  function postfix(epithet: string) {
    return name.charAt(0) + '.  the ' + epithet; // error, 'name' is possibly null
  }
  name = name || "Bob";
  return postfix("great");
}

function fixed(name: string | null): string {
  function postfix(epithet: string) {
    return name!.charAt(0) + '.  the ' + epithet; // ok
  }
  name = name || "Bob";
  return postfix("great");
}

Referensi. https://www.typescriptlang.org/docs/handbook/advanced-types.html#type-guards-and-type-assertions

Margaux
sumber