टीएलडीआर; अज्ञात फ़ंक्शन में उपयोग करने से पहले चर की जांच करना अभी भी टीएस चर को संभावित रूप से अपरिभाषित चेतावनी देता है
नीचे दिए गए कोड उदाहरण में वेरिएबल 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 जवाब
आइए कोड को थोड़ा बदल दें
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
यह भी अपने मामले में काम करता है < /ए>.
टाइपस्क्रिप्ट रनटाइम पर प्रकारों की जांच नहीं करता है और न ही प्रकार बदलता है, इसलिए 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))
}
जब आप सुनिश्चित हों कि यह एक्साइटिंग होना चाहिए और आप कुछ और नहीं बदलना चाहते हैं
const bleharr = someArr.map((val) => rstr(baseDirId!))