क्या टाइपस्क्रिप्ट समर्थन करता है? ऑपरेटर? (और, इसे क्या कहा जाता है?)


336

क्या टाइपस्क्रिप्ट वर्तमान में (या वहाँ की योजना है) सुरक्षित नेविगेशन ऑपरेटर का समर्थन करता है?.

अर्थात:

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

इसके अलावा, इस ऑपरेटर के लिए एक अधिक सामान्य नाम है (यह आकस्मिक रूप से Google के लिए कठिन है)।


3
@mattytommo आपके पास है कि c # में, इसे null coalescing ऑपरेटर कहा जाता है और ?? वाक्यविन्यास weblogs.asp.net/scottgu/archive/2007/09/20/…
basarat

2
@BasaratAli दुर्भाग्य से नहीं, मोटे तौर पर ठीक है property ?? property2, लेकिन अगर आपने कोशिश की थी property.company ?? property1.companyऔर propertyअशक्त था, तो आपको एक मिल जाएगाNullReferenceException
mattytommo

1
@mattytommo धन्यवाद मुझे अब यह मिल गया है? ' वास्तव में श्रृंखला में सभी अशक्त संदर्भों को भिगोता है। मिठाई।
बासरत

9
@mattytommo यह अब C # के लिए मौजूद है: msdn.microsoft.com/en-us/library/dn986595.aspx
Highmastdon

9
जिस Microsoft प्रतिनिधि ने हमसे मुलाकात की, उसे एल्विस ऑपरेटर कहा जाता है क्योंकि प्रश्न चिह्न एल्विस के बालों जैसा दिखता है और एक माइक्रोफ़ोन वह गा रहा है ...
ज़िमोटिक

जवाबों:


167

अद्यतन : यह टाइपस्क्रिप्ट 3.7 के रूप में समर्थित है और इसे वैकल्पिक चैनिंग कहा जाता है : https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#optional-chaining

मैं टाइपस्क्रिप्ट भाषा विनिर्देश में जो भी इसके लिए कोई संदर्भ नहीं मिल सकता है ।

जहां तक ​​इस ऑपरेटर को कॉफीस्क्रिप्ट में कॉल करने का है, इसे अस्तित्वगत ऑपरेटर कहा जाता है (विशेष रूप से, का "एक्सेसरी वेरिएंट) कहा जाता है।

से पर ऑपरेटर्स CoffeeScript के प्रलेखन :

अस्तित्ववादी ऑपरेटर के एक्सेसर वेरिएंट का ?.उपयोग संपत्तियों की श्रृंखला में अशक्त संदर्भों को भिगोने के लिए किया जा सकता है। उन .मामलों में डॉट एक्सेसर के बजाय इसका उपयोग करें जहां आधार मूल्य शून्य या अपरिभाषित हो सकता है ।

तो, इस ऑपरेटर को संदर्भित करने के लिए मौजूद ऑपरेटर का एक्सेस वेरिएंट उचित तरीका प्रतीत होता है; और टाइपस्क्रिप्ट वर्तमान में इसका समर्थन करने के लिए प्रकट नहीं होता है (हालांकि अन्य लोगों ने इस कार्यक्षमता के लिए इच्छा व्यक्त की है )।


28
"अस्तित्ववादी ऑपरेटर का एक्सेसरी वैरिएंट"। सहज रूप में। इतना आकर्षक, इसे भूलना असंभव है। :)। अत्यंत गहन उत्तर के लिए धन्यवाद।
मार्टी पिट

1
@MartyPitt ज़रूर! मैं सहमत हूं, मैं इस तरह के ऑपरेटर (सी # कृपया!) और बी) को एक बेहतर नाम (अपने सुरक्षित ब्लॉग पोस्ट से "सुरक्षित नेविगेशन" ऑपरेटर) एक अच्छा नाम है देखने के लिए प्यार करता हूँ।
डोनट

2
कोणीय इस में इसे लागू करता है टेम्पलेट्स: angular.io/guide/…
Enzoaeneas

5
कुछ अन्य भाषाओं में इसे "एल्विस" ऑपरेटर कहा जाता है
k0enf0rNL

4
यह टाइपस्क्रिप्ट 3.7.0 के लिए घोषित किया गया है ( github.com/microsoft/TypeScript/issues/… )
c_froehlich

146

एक एकल के रूप में अच्छा नहीं है? लेकिन यह काम करता है:

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

आप जितना चाहें उतना && का उपयोग कर सकते हैं:

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

33
&& तब तक मूल्यांकन करता है जब तक कि कथन सत्य है। यदि यह सही है, तो यह अंतिम मान लौटाता है। यदि यह गलत है, तो यह पहला मान लौटाता है जो गलत का मूल्यांकन करता है। वह 0, शून्य, असत्य आदि हो सकता है || पहला मान लौटाता है जो सत्य का मूल्यांकन करता है।
ए। के।

34
यदि बार को परिभाषित किया गया है, लेकिन अच्छी तरह से काम नहीं करता है, लेकिन गलत (जैसे बूलियन गलत, या शून्य) का मूल्यांकन करता है।
mt_serg

96

यह ECMAScript वैकल्पिक चाइनिंग विनिर्देश में परिभाषित किया गया है, इसलिए जब हम इस पर चर्चा करते हैं , तो हमें संभवतः वैकल्पिक श्रृंखलन का उल्लेख करना चाहिए । संभवतः कार्यान्वयन:

const result = a?.b?.c;

इसका एक लंबा और छोटा पहलू यह है कि टाइपस्क्रिप्ट टीम ECMAScript विनिर्देश की प्रतीक्षा कर रही है ताकि वे और अधिक सख्त हो सकें, इसलिए उनका कार्यान्वयन भविष्य में गैर-ब्रेकिंग हो सकता है। अगर वे अब कुछ लागू करते हैं, तो ईसीएमएस्क्रिप्ट को उनके विनिर्देश को फिर से परिभाषित करने पर बड़े बदलावों की आवश्यकता होगी।

देख वैकल्पिक चैनिंग विशिष्टता

जहाँ कुछ भी कभी भी मानक जावास्क्रिप्ट नहीं होता है, टाइपस्क्रिप्ट टीम उन्हें फिट होने के रूप में लागू कर सकती है, लेकिन भविष्य के ECMAScript परिवर्धन के लिए, वे शब्दार्थों को संरक्षित करना चाहते हैं, भले ही वे जल्दी पहुंच दें, क्योंकि उनके पास कई अन्य विशेषताओं के लिए है।

शॉर्ट कट्स

तो सभी JavaScripts फंकी ऑपरेटर्स उपलब्ध हैं, जिसमें टाइप रूपांतरण जैसे ...

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

मैनुअल समाधान

लेकिन सवाल पर वापस। मेरे पास एक उदाहरण है कि आप जावास्क्रिप्ट में एक समान काम कैसे कर सकते हैं (और इसलिए टाइपस्क्रिप्ट) हालांकि मैं निश्चित रूप से यह सुझाव नहीं दे रहा हूं कि यह एक सुशोभित है जैसा कि आप वास्तव में हैं।

(foo||{}).bar;

तो अगर fooहै undefinedपरिणाम है undefinedऔर यदि fooपरिभाषित और है एक संपत्ति नामितbar एक मूल्य होता है, नतीजा यह है कि मूल्य है।

मैंने JSFiddle पर एक उदाहरण दिया

यह लंबे उदाहरणों के लिए काफी स्केच दिखता है।

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

श्रृंखला समारोह

यदि आप छोटे संस्करण के लिए बेताब हैं, जबकि विनिर्देश अभी भी हवा में है, तो मैं कुछ मामलों में इस पद्धति का उपयोग करता हूं। यह अभिव्यक्ति का मूल्यांकन करता है और एक डिफ़ॉल्ट लौटाता है यदि श्रृंखला संतुष्ट नहीं हो सकती है या अशक्त / अपरिभाषित हो सकती है (ध्यान दें कि !=यहां महत्वपूर्ण है, हम उपयोग नहीं करना चाहते हैं !==क्योंकि हम यहां सकारात्मक सकारात्मकता चाहते हैं)।

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
दिलचस्प लेकिन मेरे मामले में (this.loop || {}).nativeElementयह कहते हुए Property 'nativeElement' does not exist on type '{}'. any this.looptypeof angular.io/api/core/ElementRef
kuncevic.dev

@Kuncevic - आपको या तो ... 1) के स्थान पर एक संगत डिफ़ॉल्ट प्रदान करना है {}, या 2) संकलक को चुप कराने के लिए एक प्रकार के दावे का उपयोग करना है।
फेंटन

मान fooलेना एक वास्तविक उपयोगी वस्तु है: (foo || {}).barआम तौर पर टाइपस्क्रिप्ट में संकलित {}नहीं किया जा सकता क्योंकि यह उसी प्रकार का नहीं होगा foo। यही समस्या है कि @ VeganHunter के समाधान से बचने का लक्ष्य है।
सिमोन_वेर 5

1
@Simon_Weaver तब (foo || {बार})। बार कंपाइलर को आसानी से चलने देगा और मुझे लगता है कि वर्बोसिटी स्वीकार्य है।
हार्प्स Har ’

@ व्हार्स वास्तव में यह केवल संकलन करता है यदि बार को एक चर के रूप में परिभाषित किया गया है, जो कि इसकी सबसे अधिक संभावना नहीं होगी
सिमोन_विवर

82

अपडेट: हाँ अब इसका समर्थन किया गया है!

यह सिर्फ टाइपस्क्रिप्ट 3.7 के साथ जारी किया गया: https://devblogs.microsoft.com/typescript/announcing-typescript-3-7/

इसे वैकल्पिक चैनिंग कहा जाता है : https://devblogs.microsoft.com/typescript/announcing-typescript-3-7/#optional-chaining

इसके साथ निम्नलिखित हैं:

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

के बराबर है:

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

पुराना उत्तर

इसके लिए github पर एक खुला सुविधा अनुरोध है जहाँ आप अपनी राय / इच्छा दे सकते हैं: https://github.com/Microsoft/TypeScript/issues/16


36

13 नवंबर, 2019 को संपादित करें!

5 नवंबर 2019 तक टाइपस्क्रिप्ट 3.7 ने भेज दिया है और यह अब ?. वैकल्पिक चेनिंग ऑपरेटर का समर्थन करता है 201 !!!

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


केवल ऐतिहासिक उद्देश्यों के लिए:

संपादित करें: मैंने फ़्रेक्स टिप्पणी के लिए धन्यवाद जवाब अपडेट किया है।

टाइपस्क्रिप्ट 2.0 का विमोचन !.यह उसी तरह नहीं है जैसा ?.(C # में सुरक्षित नेविगेटर)

अधिक विवरण के लिए यह उत्तर देखें:

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

यह केवल संकलक को बताएगा कि मान शून्य या अपरिभाषित नहीं है। यह जाँच नहीं करेगा कि मान शून्य या अपरिभाषित है।

टाइपस्क्रिप्ट गैर-नल मुखर ऑपरेटर

// 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
ऐसा नहीं है ?क्योंकि यह दावा करता है कि मूल्य परिभाषित किया गया है। ?उम्मीद है कि चुपचाप असफल / झूठे का मूल्यांकन करें। वैसे भी, अच्छा पता है।
fracz 21

1
अब जब मैं इसके बारे में सोचता हूं ... यह उत्तर बहुत ही बेकार है, क्योंकि यह "सुरक्षित नेविगेशन" नहीं करता है जो कि सी # ऑपरेटर करता है।
जोस ए

5
यह मेरे सवाल का जवाब दिया, हालांकि। मुझे पता था? c # से और इसे टाइपस्क्रिप्ट में आज़माया। यह काम नहीं किया, लेकिन मैंने देखा कि! मौजूद था, लेकिन यह नहीं जानता था कि उसने क्या किया है। मुझे आश्चर्य हुआ कि क्या यह वही था, एक Google खोज की, और इस प्रश्न के लिए अपना रास्ता ढूंढ लिया जिसने मुझे सूचित किया कि नहीं, वे अलग हैं।
लेलवेई

11

एल्विस (।) वैकल्पिक चैनिंग ऑपरेटर टाइपस्क्रिप्ट 3.7 में समर्थित है।

आप इसे शून्य मानों की जांच के लिए उपयोग कर सकते हैं: cats?.miows यदि अशक्त या अपरिभाषित है तो अशक्त रिटर्न देता है।

आप इसे वैकल्पिक विधि कॉलिंग के लिए भी उपयोग कर सकते हैं: cats.doMiow?.(5)यदि यह मौजूद है तो doMiow कॉल करेगा।

संपत्ति का उपयोग भी संभव है: cats?.['miows'] :।

संदर्भ: https://devblogs.microsoft.com/typescript/announcing-typescript-3-7-beta/


कृपया मुझे सही करें, लेकिन एल्विस ऑपरेटर कम से कम कोटलिन में है ?:। क्या आपके पास एक संदर्भ है?
रेकी


1
यह जल्द ही सादे JS में समर्थित होगा - developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Mottie

1
टाइपस्क्रिप्ट 3.7 की घोषणा में इसका उल्लेख है: devblogs.microsoft.com/typescript/announcing-typescript-3-7
György Balássy

10

?.टाइपस्क्रिप्ट संस्करण 2.0 में ऑपरेटर का समर्थन नहीं किया गया है ।

इसलिए मैं निम्नलिखित फ़ंक्शन का उपयोग करता हूं:

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

उपयोग इस तरह दिखता है:

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

साथ ही, आप एक डिफ़ॉल्ट मान सेट कर सकते हैं:

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

यह Visual Studio में IntelliSense के साथ वास्तव में अच्छी तरह से काम करता है।


1
यही वह है जिसकी तलाश में मैं हूं! यह टाइपस्क्रिप्ट 2.1.6 में काम करता है।
रजब शकीरोव

5
या आप इसे कॉल कर सकते हैं elvis<T>;-)
सिमोन_विवर

3
सिमोन_वर, मैं इसे "उदास मसख़रा"
कहता हूं

5

यह अंत में यहाँ है!

कुछ उदाहरण निम्नलिखित हैं:

// 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?.()

लेकिन यह आपकी धारणा के समान काम नहीं करता है।

इसके बजाय मूल्यांकन

foo?.bar

इस छोटे से कोड स्निपेट के लिए हम सभी लिखने के आदी हैं

foo ? foo.bar : null

यह वास्तव में मूल्यांकन करता है

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

जो एक खाली स्ट्रिंग, 0 या झूठ की तरह सभी फाल्सी मूल्यों के लिए काम करता है।

मेरे पास इस बारे में स्पष्टीकरण नहीं है कि वे इसे क्यों नहीं संकलित करते हैं foo == null


3

हमने फोनट्रेड्र पर काम करते समय यह उपयोग विधि बनाई जो आपको टाइपस्क्रिप्ट के साथ गहरे गुणों के लिए टाइप-सेफ एक्सेस दे सकती है:

/**
 * 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);


ठंडा!! क्या कोई कैविएट है? मेरे पास लगभग 20 गेटर्स लिखने के लिए एक रैपर क्लास है, उनमें से हर एक में निम्न प्रकार का रिटर्न है - और सभी क्षेत्रों को शून्य से चेक करना होगाreturn this.entry.fields.featuredImage.fields.file.url;
Drenai

एकमात्र कैविट संभवतः एक प्रदर्शन प्रभाव हो सकता है, लेकिन मैं बोलने के लिए योग्य नहीं हूं कि विभिन्न JITers इसे कैसे संभालते हैं।
रे सुलेजर

2

मैं आम तौर पर इस दृष्टिकोण (प्रदर्शन चिंताओं के लिए बाहर) की सिफारिश नहीं करता हूं, लेकिन आप किसी ऑब्जेक्ट को उथले करने के लिए प्रसार ऑपरेटर का उपयोग कर सकते हैं, जिस पर आप संपत्ति का उपयोग कर सकते हैं।

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

यह काम करता है क्योंकि 'FirstName' का प्रकार 'प्रचारित' है।

जब मैं एक find(...)अभिव्यक्ति है कि अशक्त वापस आ सकते हैं और मैं इसे से एक एकल संपत्ति की जरूरत है मैं इस सबसे अधिक बार उपयोग करेंगे :

 // 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;

टाइपस्क्रिप्ट के प्रकार के साथ कुछ किनारे मामले हो सकते हैं और यह संकलन नहीं करेगा, लेकिन यह आम तौर पर काम करना चाहिए।


2

इसे वैकल्पिक चैनिंग कहा जाता है और यह टाइपस्क्रिप्ट 3.7 में है

वैकल्पिक चेनिंग हमें कोड लिखने की सुविधा देता है जहां हम कुछ भावों को चलाना बंद कर सकते हैं यदि हम अशक्त या अपरिभाषित हैं


0

जैसा कि पहले उत्तर दिया गया था, यह अभी भी माना जा रहा है, लेकिन यह अब तक कुछ वर्षों के लिए पानी में मर चुका है

मौजूदा उत्तरों पर निर्माण, यहाँ सबसे संक्षिप्त मैनुअल संस्करण है जिसके बारे में मैं सोच सकता हूँ:

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'

यह गायब संपत्ति त्रुटियों पर चुपचाप विफल रहता है। यह डिफ़ॉल्ट मान निर्धारित करने के लिए मानक सिंटैक्स पर वापस आ जाता है, जिसे पूरी तरह से छोड़ा जा सकता है।


हालांकि यह सरल मामलों के लिए काम करता है, यदि आपको अधिक जटिल सामान की आवश्यकता होती है जैसे कि फ़ंक्शन को कॉल करना और फिर परिणाम पर किसी संपत्ति तक पहुंचना, तो किसी भी अन्य त्रुटियों को भी निगल लिया जाता है। खराब डिजाइन।

उपरोक्त मामले में, यहां पोस्ट किए गए अन्य उत्तर का एक अनुकूलित संस्करण बेहतर विकल्प है:

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'

एक अधिक जटिल उदाहरण:

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

आप दूसरे तरीके से भी जा सकते हैं और लॉडश जैसी किसी चीज़ का उपयोग कर सकते हैं _.get()। यह संक्षिप्त है, लेकिन संकलक उपयोग की गई संपत्तियों की वैधता का न्याय नहीं कर पाएगा:

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

0

अभी तक (सितंबर, 2019 तक) नहीं है, लेकिन चूंकि "सुरक्षित नेविगेशन ऑपरेटर" अब स्टेज 3 पर है , इसलिए इसे टाइपस्क्रिप्ट में लागू किया जा रहा है।

अपडेट के लिए यह समस्या देखें:

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

कई इंजनों का प्रारंभिक कार्यान्वयन है:

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 के माध्यम से )

अब आप इसका समर्थन करने के लिए एक प्लगइन स्थापित कर सकते हैं:

npm install --save-dev ts-optchain

अपने tsconfig.json में:

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

मुझे उम्मीद है कि यह जवाब अगले 6 महीने में आउट ऑफ डेट हो जाएगा, लेकिन उम्मीद है कि इस बीच किसी को मदद मिलेगी।


-1

_.get(obj, 'address.street.name')जावास्क्रिप्ट के लिए बढ़िया काम करता है जहाँ आपके पास कोई प्रकार नहीं है। लेकिन टाइपस्क्रिप्ट के लिए हमें वास्तविक एल्विस ऑपरेटर की आवश्यकता है!

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.