टीएलडीआर; अज्ञात फ़ंक्शन में उपयोग करने से पहले चर की जांच करना अभी भी टीएस चर को संभावित रूप से अपरिभाषित चेतावनी देता है

नीचे दिए गए कोड उदाहरण में वेरिएबल baseDirId की जांच की जाती है यदि अपरिभाषित है तो array.map फ़ंक्शन को पास किया गया है लेकिन TS चेतावनी baseDirId को अपरिभाषित किया जा सकता है।

// टाइपप्रति खेल का मैदान लिंक


const rstr = async (a: string) => {
  return a + "bleh"
}

const args: { baseDirId: string | undefined } = {
  baseDirId: "someid"
  // baseDirId: undefined
}

const someArr = ["bleh1", "bleh2"]

const func1 = async (): Promise<void> => {
  try {
    // Assume baseDirId can be undefined
    let baseDirId = args.baseDirId

    // Trigger if baseDirId is undefined
    if (!baseDirId) {
      const baseDirObj = { id: "valid string" }
      baseDirId = baseDirObj.id
    }
    console.log(typeof baseDirId)

    // baseDirId cant be anything other than a string 
    if (typeof baseDirId !== "string") {
      return Promise.reject("Base Dir response invalid")
    }

    // Why is baseDirId `string | undefined` inside rstr call below even after above checks
    const bleharr = someArr.map((val) => rstr(baseDirId))
    console.log(await Promise.all(bleharr))
  } catch (err) {
    console.error(err)
  }
}

func1().catch(err => console.error(err))

क्या कोई संभावित मामला है जहां baseDirId undefined हो सकता है?

TS इसकी अनुमति क्यों नहीं देगा? इसे करने का बेहतर तरीका?

2
Solaris 18 अप्रैल 2021, 14:04

2 जवाब

सबसे बढ़िया उत्तर

आइए कोड को थोड़ा बदल दें

 return () => someArr.map((val) => rstr(baseDirId))

इसलिए .map को सीधे कॉल करने के बजाय इसे बाद में चलाया जा सकता है। हो सकता है कि कुछ अन्य कोड ने इस बीच baseDirId में अपरिभाषित लिखा हो। इसलिए टाइपस्क्रिप्ट को सही ढंग से अनुमान लगाने के लिए, टाइपस्क्रिप्ट को यह जांचना होगा कि कोई अन्य कोड कभी-कभी वेरिएबल को ओवरराइड नहीं करता है। यह काफी जटिल कार्य है (यह कुछ कोने के मामलों में असंभव भी हो सकता है)। इसके अलावा यह और भी जटिल हो जाता है यदि हमारे आंतरिक कार्य को कई स्थानों पर बुलाया जाता है:

let mutable: string | undefined = /*...*/;
const inner = () => fn(mutable); // << how to infer this?

mightCall(inner); // if called back here, mutable would be "string | undefined"
if(typeof mutable === "string") mightCall(inner); // if called here, mutable could be narrowed down to "string", but only if mightCall calls back synchronously

mutable = undefined; // if mightCall calls back asynchronously, 'mutable' would have to be inferred as undefined

इसलिए जब फ़ंक्शन बाहरी दायरे से चर का उपयोग करते हैं, तो टाइपस्क्रिप्ट कंपाइलर सबसे व्यापक संभव प्रकार मानता है। टाइप संकुचन केवल फ़ंक्शन के शरीर के लिए ही काम करता है। प्रकार को कम करने के लिए आपको या तो एक प्रकार के अभिकथन की आवश्यकता होगी, या वैकल्पिक रूप से मान को const में कॉपी करें:

 let mutable: string | undefined = /*...*/;
 if(typeof mutable !== "string") return;
 // mutable get's narrowed down to string here due to the typeof type guard
 const immutable = mutable;
  //        ^ inferred as string, this is the widest possible type

यह भी अपने मामले में काम करता है < /ए>.

2
Jonas Wilms 18 अप्रैल 2021, 12:16

टाइपस्क्रिप्ट रनटाइम पर प्रकारों की जांच नहीं करता है और न ही प्रकार बदलता है, इसलिए baseDirId टाइप हमेशा string | undefined रहेगा जब तक कि आप टाइप के लिए संकीर्ण प्रकार या कुछ और नहीं करते हैं, इसलिए ऐसे कई विकल्प हैं जिन्हें आप आजमा सकते हैं।

<मजबूत>1. डिफ़ॉल्ट का उपयोग करें

let baseDirId = args.baseDirId || "valid string"

<मजबूत>2. सशर्त मान जांच करें

if(args.baseDirId){
  let baseDirId = args.baseDirId
  // ...
  // do something you want
}

लेकिन आप इसे सीधे निम्नलिखित स्निपेट में नहीं कर सकते, क्योंकि आपने baseDirId घोषित करने के लिए let का उपयोग किया था, और फिर यह काम नहीं करेगा क्योंकि इसे किसी भी समय undefined में बदला जा सकता है समय जब तक कि इसे const के माध्यम से घोषित नहीं किया जाता है

if(baseDirId){
  const bleharr = someArr.map((val) => rstr(baseDirId))
}

3. ! गैर-शून्य अभिकथन ऑपरेटर

जब आप सुनिश्चित हों कि यह एक्साइटिंग होना चाहिए और आप कुछ और नहीं बदलना चाहते हैं

const bleharr = someArr.map((val) => rstr(baseDirId!))
1
zixiCat 18 अप्रैल 2021, 12:02