Typescript destekliyor mu? Şebeke? (Buna ne denir?)


337

Typescript şu anda güvenli navigasyon operatörünü şu anda destekliyor mu (ya da planlıyorsa)?.

yani:

var thing = foo?.bar
// same as:
var thing = (foo) ? foo.bar : null;

Ayrıca, bu operatör için daha yaygın bir ad var mı (Google için bu son derece zor).


3
@mattytommo c # var, onun boş birleştirici işleç denir ve kullanır ?? sözdizimi weblogs.asp.net/scottgu/archive/2007/09/20/…
basarat

2
@BasaratAli Maalesef birleşme iyi property ?? property2, ama denediyseniz property.company ?? property1.companyve propertynull olsaydınız, birNullReferenceException
mattytommo

1
@mattytommo Teşekkürler Şimdi anladım '?.' aslında zincirdeki tüm boş referansları emer. Tatlı.
Basarat

9
@mattytommo Bu şimdi C # için mevcut: msdn.microsoft.com/en-us/library/dn986595.aspx
Highmastdon

9
Bizi ziyaret eden Microsoft temsilcisi, Elvis'in saçına ve şarkı söylediği bir mikrofona benzediği için Elvis operatörü olarak adlandırdı ...
Zymotik

Yanıtlar:


168

Güncelleme : TypeScript 3.7'den itibaren desteklenir ve İsteğe bağlı zincirleme olarak adlandırılır : https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#optional-chaining

TypeScript dil belirtiminde herhangi bir referans bulamıyorum .

CoffeeScript'te bu operatöre ne ad verileceği konusunda, buna varoluşçu operatör (özellikle varoluşçu operatörün "erişimci varyantı") denir .

Gönderen İşletmecilere CoffeeScript belgelerine :

Varoluşçu operatörün erişimci varyantı, ?.bir özellik zincirinde boş referansları emmek için kullanılabilir. .Taban değerinin boş veya tanımsız olabileceği durumlarda nokta erişimcisi yerine bunu kullanın .

Dolayısıyla, varoluşçu operatörün erişimci varyantı bu operatöre başvurmak için uygun bir yol gibi görünmektedir; ve TypeScript şu anda bunu desteklemiyor gibi görünmektedir (ancak diğerleri bu işlevsellik için bir istek ifade ettiler ).


28
msgstr "varoluşçu operatörün erişimci varyantı". Doğal olarak. Çok akılda kalıcı, unutmak neredeyse imkansız. :). Son derece kapsamlı cevap için teşekkürler.
Marty Pitt

1
@MartyPitt Elbette! Kabul ediyorum, a) böyle bir operatörün daha geniş bir şekilde benimsenmesi (C # lütfen!) Ve b) daha iyi bir isim (bağlantılı blog postanızdaki "güvenli navigasyon" operatörünün hoş bir zil sesi vardır).
Halka

2
'S şablonları Açısal uygular bu: angular.io/guide/...
Enzoaeneas

5
Diğer bazı dillerde "Elvis" operatörü denir
k0enf0rNL 26:08

4
TypeScript 3.7.0 için duyuruldu ( github.com/microsoft/TypeScript/issues/… )
c_froehlich

146

Tek bir kadar güzel değil, ama işe yarıyor:

var thing = foo && foo.bar || null;

İstediğiniz kadar && kullanabilirsiniz:

var thing = foo && foo.bar && foo.bar.check && foo.bar.check.x || null;

33
&& ifadenin doğru olduğu sürece değerlendirir. Doğruysa, son değeri döndürür. False olursa, false olarak değerlendirilen ilk değeri döndürür. Bu 0, boş, yanlış vb. Olabilir || true olarak değerlendirilen ilk değeri döndürür.
A. KR

34
Çubuk tanımlanmışsa ancak yanlış olarak değerlendirilirse (boolean false veya zero gibi) iyi çalışmaz.
mt_serg

96

Bu, ECMAScript İsteğe Bağlı Zincirleme spesifikasyonunda tanımlanmıştır, bu nedenle bunu tartıştığımızda muhtemelen isteğe bağlı zincirlemeye başvurmalıyız . Muhtemel uygulama:

const result = a?.b?.c;

Bunun uzun ve kısa kısmı, TypeScript ekibinin ECMAScript spesifikasyonunun sıkılaştırılmasını beklemesi, böylece uygulamalarının gelecekte kırılmaması olabilir. Eğer şimdi bir şey uygularlarsa, ECMAScript teknik özelliklerini yeniden tanımlarsa büyük değişikliklere ihtiyaç duyar.

Görmek İsteğe Bağlı Zincirleme Spesifikasyonu

Bir şeyin asla standart JavaScript olmayacağı durumlarda, TypeScript ekibi uygun gördükleri gibi uygulayabilir, ancak gelecekteki ECMAScript eklemeleri için, diğer birçok özellikte olduğu gibi erken erişim verseler bile anlambilimi korumak isterler.

Kısa Kesimler

Böylece tüm JavaScripts funky operatörleri, gibi tür dönüşümleri de mevcuttur ...

var n: number = +myString; // convert to number
var b: bool = !!myString; // convert to bool

Manuel Çözüm

Ama soruya geri dönelim. JavaScript (ve bu nedenle TypeScript) benzer bir şey nasıl yapabileceğinizi açık bir örnek var, ancak kesinlikle gerçekten sonra özelliği olarak zarif olduğunu düşündürmüyorum.

(foo||{}).bar;

Yani eğer foobir undefinedsonucudur undefinedve eğer footanımlanmış ve adında bir özellik vardır barbir değere sahiptir, sonuç o değerdir.

JSFiddle'a bir örnek verdim .

Bu, daha uzun örnekler için oldukça kabataslak görünüyor.

var postCode = ((person||{}).address||{}).postcode;

Zincir İşlevi

Spesifikasyon hala havadayken daha kısa bir versiyon için umutsuzsanız, bazı durumlarda bu yöntemi kullanıyorum. Bu ifadeyi değerlendirir ve zincir memnun veya tanımsız boş / yukarı uçları (not edilemezse varsayılan döndürür !=biz burada önemli olan yok kullanmak istiyorum !==biz burada olumlu hokkabazlık istemek biraz gibi).

function chain<T>(exp: () => T, d: T) {
    try {
        let val = exp();
        if (val != null) {
            return val;
        }
    } catch { }
    return d;
}

let obj1: { a?: { b?: string }} = {
    a: {
        b: 'c'
    }
};

// 'c'
console.log(chain(() => obj1.a.b, 'Nothing'));

obj1 = {
    a: {}
};

// 'Nothing'
console.log(chain(() => obj1.a.b, 'Nothing'));

obj1 = {};

// 'Nothing'
console.log(chain(() => obj1.a.b, 'Nothing'));

obj1 = null;

// 'Nothing'
console.log(chain(() => obj1.a.b, 'Nothing'));

1
İlginç ama benim durumumda (this.loop || {}).nativeElementsöyleyerek Property 'nativeElement' does not exist on type '{}'. any this.looptypeof angular.io/api/core/ElementRef
kuncevic.dev

@Kuncevic - gerek ... 1) yerine uyumlu bir varsayılan sağlamak {}veya 2) derleyiciyi susturmak için bir tür iddiası kullanmak.
Fenton

Varsayım foogerçek bir yararlı nesnedir: (foo || {}).bargenellikle aynı metin {}türünde olmayacağından daktiloda derlenmeyecektir foo. @ VeganHunter çözümünün kaçınmayı amaçladığı sorun budur.
Simon_Weaver

1
@Simon_Weaver (foo || {bar}) .bar derleyicinin sorunsuz çalışmasına izin verecek ve ayrıntıların kabul edilebilir olduğunu düşünüyorum.
Harps

@harps aslında bu sadece bar bir değişken olarak tanımlanırsa derlenir, ki bu büyük olasılıkla olmayacaktır
Simon_Weaver

82

Güncelleme: Evet artık destekleniyor!

TypeScript 3.7 ile piyasaya çıktı: https://devblogs.microsoft.com/typescript/announcing-typescript-3-7/

İsteğe bağlı zincirleme denir : https://devblogs.microsoft.com/typescript/announcing-typescript-3-7/#optional-chaining

Bununla birlikte:

let x = foo?.bar.baz(); 

şuna eşittir:

let x = (foo === null || foo === undefined) ?
    undefined :
    foo.bar.baz();

Eski cevap

Github'da, görüşünüzü / arzunuzu dile getirebileceğiniz açık bir özellik isteği var: https://github.com/Microsoft/TypeScript/issues/16


36

Edit 13 Kasım 2019!

5 Kasım 2019'dan itibaren TypeScript 3.7 sevk edildi ve şimdi ?. isteğe bağlı zincirleme operatörünü supports !!!

https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#optional-chaining


Yalnızca Tarihsel Amaçlar İçin:

Edit: Cevabı fracz yorum sayesinde güncelledim.

TypeScript 2.0 çıktı (C # 'da Güvenli Gezinme) !.ile aynı değil?.

Daha fazla ayrıntı için bu cevaba bakınız:

https://stackoverflow.com/a/38875179/1057052

Bu derleyiciye yalnızca değerin boş veya tanımsız olmadığını bildirir. Bu , değerin boş veya tanımsız olduğunu kontrol etmez .

TypeScript Null olmayan onaylama işleci

// Compiled with --strictNullChecks
function validateEntity(e?: Entity) {
    // Throw exception if e is null or invalid entity
}

function processEntity(e?: Entity) {
    validateEntity(e);
    let s = e!.name;  // Assert that e is non-null and access name
}

4
Aynı değil ?çünkü iddia değer tanımlandığını. ?sessizce başarısız / yanlış olarak değerlendirilir. Her neyse, bilmek güzel.
fracz

1
Şimdi bunun hakkında düşünüyorum ... Bu cevap oldukça anlamsız, çünkü C # operatörün yaptığı "güvenli navigasyon" yapmaz.
Jose A

5
Ancak bu sorumu yanıtladı. Biliyor muyum? c # dan ve daktiloda denedim. İşe yaramadı, ama gördüm. var ama ne yaptığını bilmiyordu. Aynı olup olmadığını merak ettim, bir google araması yaptı ve bana hayır olduğunu söyleyen bu soruya giden yolu bulduğumu, farklı olduklarını merak ettim.
Llewey

11

Elvis (?.) İsteğe Bağlı Zincirleme İşleci, TypeScript 3.7'de desteklenir.

Null değerleri kontrol etmek için kullanabilirsiniz: cats?.miowskediler null veya tanımsızsa null değerini döndürür.

İsteğe bağlı yöntem çağrısı için de kullanabilirsiniz: cats.doMiow?.(5) varsa doMiow'u çağırır.

Mülkiyet erişimi de mümkündür: cats?.['miows'].

Referans: https://devblogs.microsoft.com/typescript/announcing-typescript-3-7-beta/


Lütfen beni düzeltin, ama Elvis operatörü en azından Kotlin'de ?:. Referansınız var mı?
rekire



1
TypeScript 3.7 sürümünün duyurusu bundan bahsediyor: devblogs.microsoft.com/typescript/announcing-typescript-3-7
György Balássy

10

Operatör ?., TypeScript sürüm 2.0'da desteklenmez .

Bu yüzden aşağıdaki işlevi kullanıyorum:

export function o<T>(someObject: T, defaultValue: T = {} as T) : T {
    if (typeof someObject === 'undefined' || someObject === null)
        return defaultValue;
    else
        return someObject;
}

kullanım şöyle görünür:

o(o(o(test).prop1).prop2

artı, varsayılan bir değer ayarlayabilirsiniz:

o(o(o(o(test).prop1).prop2, "none")

Visual Studio'daki IntelliSense ile gerçekten iyi çalışıyor.


1
Tam da aradığım şey buydu! Yazı tipinde çalışır 2.1.6.
Rajab Shakirov

5
ya da diyebilirsiniz elvis<T>;-)
Simon_Weaver

3
Simon_Weaver, buna "üzgün palyaço"
diyorum

5

O sonunda burada!

İşte birkaç örnek:

// properties
foo?.bar
foo?.bar()
foo?.bar.baz()
foo?.bar?.baz()

// indexing
foo?.[0]
foo?.['bar']

// check if a function is defined before invoking
foo?.()
foo.bar?.()
foo?.bar?.()

Ancak varsayımınızla tam olarak aynı şekilde çalışmaz.

Değerlendirmek yerine

foo?.bar

Bu küçük kod pasajına hepimiz yazmaya alışkınız

foo ? foo.bar : null

aslında değerlendirir

(foo === null || foo === undefined) ?
    undefined :
    foo.bar

0 veya false gibi boş bir dize gibi tüm falsey değerleri için çalışır.

Neden derlemediklerine dair bir açıklamam yok foo == null


3

Phonetradr üzerinde çalışırken bu yazıt yöntemini, Typcript ile derin özelliklere yazabileceğiniz güvenli bir erişim sağlayabildik:

/**
 * Type-safe access of deep property of an object
 *
 * @param obj                   Object to get deep property
 * @param unsafeDataOperation   Function that returns the deep property
 * @param valueIfFail           Value to return in case if there is no such property
 */
export function getInSafe<O,T>(obj: O, unsafeDataOperation: (x: O) => T, valueIfFail?: any) : T {
    try {
        return unsafeDataOperation(obj)
    } catch (error) {
        return valueIfFail;
    }
}

//Example usage:
getInSafe(sellTicket, x => x.phoneDetails.imeiNumber, '');

//Example from above
getInSafe(foo, x => x.bar.check, null);


Güzel!! Herhangi bir uyarı var mı? Yazmak için yaklaşık 20 alıcıları ile bir sarıcı sınıf var, her biri aşağıdaki tür dönüş vardır - ve tüm alanlar boş olmalıdırreturn this.entry.fields.featuredImage.fields.file.url;
Drenai

Tek uyarı muhtemelen bir performans etkisi olabilir, ancak çeşitli JITER'lerin bunu nasıl ele aldığını konuşmak için nitelikli değilim.
Ray Suelzer

2

Genellikle bu yaklaşımı önermiyorum (performans kaygılarına dikkat edin), ancak daha sonra özelliğe erişebileceğiniz bir nesneyi sığ klonlamak için yayma işlecini kullanabilirsiniz.

 const person = { personId: 123, firstName: 'Simon' };
 const firstName = { ...person }.firstName;

Bu, 'firstName' türünün 'yayıldığı' için çalışır.

Ben find(...)null dönebilir bir ifade var ve ondan tek bir özellik gerektiğinde bu en sık kullanacağım :

 // this would cause an error (this ID doesn't exist)
 const people = [person];
 const firstName2 = people.find(p => p.personId == 999).firstName;

 // this works - but copies every property over so raises performance concerns
 const firstName3 = { ...people.find(p => p.personId == 999) }.firstName;

Yazı tipinin türleri etkileme biçimiyle ilgili bazı uç durumlar olabilir ve bu derlenmez, ancak bu genellikle işe yaramalıdır.


2

Buna isteğe bağlı zincirleme denir ve dakikadır 3.7

İsteğe bağlı zincirleme, boş veya tanımsız bir şekilde karşılaşırsak bazı ifadeleri çalıştırmayı hemen durdurabileceğimiz kod yazmamızı sağlar


0

Daha önce yanıtlandığı gibi, şu anda hala dikkate alınmaktadır, ancak birkaç yıldır suda ölüdür .

Mevcut cevaplara dayanarak, düşünebileceğim en kısa manuel sürüm:

jsfiddle

function val<T>(valueSupplier: () => T): T {
  try { return valueSupplier(); } catch (err) { return undefined; }
}

let obj1: { a?: { b?: string }} = { a: { b: 'c' } };
console.log(val(() => obj1.a.b)); // 'c'

obj1 = { a: {} };
console.log(val(() => obj1.a.b)); // undefined
console.log(val(() => obj1.a.b) || 'Nothing'); // 'Nothing'

obj1 = {};
console.log(val(() => obj1.a.b) || 'Nothing'); // 'Nothing'

obj1 = null;
console.log(val(() => obj1.a.b) || 'Nothing'); // 'Nothing'

Sadece eksik özellik hataları sessizce başarısız. Tamamen atlanabilecek varsayılan değeri belirlemek için standart sözdizimine geri döner.


Bu basit durumlarda işe yarar, ancak bir işlevi çağırmak ve daha sonra sonuçtaki bir özelliğe erişmek gibi daha karmaşık şeylere ihtiyacınız varsa, diğer hatalar da yutulur. Kötü tasarım.

Yukarıdaki durumda, burada yayınlanan diğer cevabın optimize edilmiş bir versiyonu daha iyi bir seçenektir:

jsfiddle

function o<T>(obj?: T, def: T = {} as T): T {
    return obj || def;
}

let obj1: { a?: { b?: string }} = { a: { b: 'c' } };
console.log(o(o(o(obj1).a)).b); // 'c'

obj1 = { a: {} };
console.log(o(o(o(obj1).a)).b); // undefined
console.log(o(o(o(obj1).a)).b || 'Nothing'); // 'Nothing'

obj1 = {};
console.log(o(o(o(obj1).a)).b || 'Nothing'); // 'Nothing'

obj1 = null;
console.log(o(o(o(obj1).a)).b || 'Nothing'); // 'Nothing'

Daha karmaşık bir örnek:

o(foo(), []).map((n) => n.id)

Diğer tarafa da gidebilir ve Lodash gibi bir şey kullanabilirsiniz _.get(). Özlüdür, ancak derleyici kullanılan özelliklerin geçerliliğini değerlendiremez:

console.log(_.get(obj1, 'a.b.c'));

0

Henüz değil (Eylül 2019 itibariyle), ancak "güvenli navigasyon operatörü" artık 3. Aşama'da , TypeScript'te uygulanmaktadır.

Güncellemeler için bu sorunu izleyin:

https://github.com/microsoft/TypeScript/issues/16

Birçok motorun erken uygulamaları vardır:

JSC: https://bugs.webkit.org/show_bug.cgi?id=200199

V8: https://bugs.chromium.org/p/v8/issues/detail?id=9553

SM: https://bugzilla.mozilla.org/show_bug.cgi?id=1566143

( https://github.com/tc39/proposal-optional-chaining/issues/115#issue-475422578 aracılığıyla )

Şimdi desteklemek için bir eklenti yükleyebilirsiniz:

npm install --save-dev ts-optchain

Tsconfig.json dosyasında:

// tsconfig.json
{
    "compilerOptions": {
        "plugins": [
            { "transform": "ts-optchain/transform" },
        ]
    },
}

Önümüzdeki 6 ay içinde bu cevabın güncelliğini yitirmesini bekliyorum, ancak umarım bu arada birine yardımcı olacaktır.


-1

_.get(obj, 'address.street.name')türünüzün olmadığı JavaScript için harika çalışır. Ancak TypeScript için gerçek Elvis operatörüne ihtiyacımız var !

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.