टाइपस्क्रिप्ट: मैप्ड प्रकार में सूचकांक हस्ताक्षर
मैं प्रकार { 'k': number, [s: string]: any }और सार को कैसे ले जा सकता हूं 'k'और number? मैं एक प्रकार अन्य नाम हैं, चाहते हैं Tऐसी है कि T<'k', number>कहा प्रकार देता है।
निम्नलिखित उदाहरण पर विचार करें:
function f(x: { 'k': number, [s: string]: any }) {} // ok
type T_no_params = { 'k': number, [s: string]: any }; // ok
type T_key_only<k extends string> = { [a in k]: number }; // ok
type T_value_only<V> = { 'k': V, [s: string]: any}; // ok
type T_key_and_index<k extends string, V> = { [a in k]: V, [s: string]: any };// ?
{ 'k': number, [s: string]: any}फ़ंक्शन के पैरामीटर के प्रकार के रूप में सीधे उपयोग करनाfकाम करता है।- अनुलोम-विलोम
[s: string]: anyभाग का उपयोग करनाtypeकाम करता है - का प्रयोग
k extends stringमेंtype-alias भी काम करता है - जब समान -काल में संयोजन किया
k extends stringजाता है , तो मुझे एक पार्स त्रुटि मिलती है (सिमेंटिक त्रुटि भी नहीं, यह मान्य सिंटैक्स भी नहीं लगता है)।[s: string]: anytype
यह यहाँ काम करने लगता है:
type HasKeyValue<K extends string, V> = { [s: string]: any } & { [S in K]: V }
लेकिन यहाँ, मैं यह नहीं समझ सकता कि यह अतिरिक्त गुणों के बारे में शिकायत क्यों नहीं करता है (दाईं ओर के प्रकार को &अतिरिक्त गुणों वाली वस्तुओं की अनुमति नहीं देना चाहिए)।
संपादित करें :
उत्तर में कई बार उल्लेख किया गया है कि &चौराहा ऑपरेटर है, जिसे सेट-प्राइमरी चौराहे के समान व्यवहार करना है। यह, हालांकि, ऐसा नहीं है जब यह अतिरिक्त गुणों के उपचार की बात आती है, जैसा कि निम्नलिखित उदाहरण दर्शाता है:
function f(x: {a: number}){};
function g(y: {b: number}){};
function h(z: {a: number} & {b: number}){};
f({a: 42, b: 58}); // does not compile. {a: 42, b: 58} is not of type {a: number}
g({a: 42, b: 58}); // does not compile. {a: 42, b: 58} is not of type {b: number}
h({a: 42, b: 58}); // compiles!
इस उदाहरण में, ऐसा लगता है जैसे कि {a: 42, b: 58}न तो प्रकार का है {a: number}, न ही प्रकार का है {b: number}, लेकिन यह किसी भी तरह चौराहे पर समाप्त होता है {a: number} & {b: number}। यह सेट-थ्योरेटिकल चौराहा कैसे काम करता है।
यही कारण है कि मेरे अपने &-प्रोपोसल मुझे इतने संदिग्ध लग रहे थे। मैं सराहना करता हूं कि अगर कोई यह बताए कि कैसे एक छोटे से प्रकार को "इंटरसेक्टिंग" किया { [s: string]: any }जा सकता है, जिससे टाइप छोटा होने के बजाय "बड़ा" हो सकता है।
मैंने प्रश्न देखे हैं
- टाइपस्क्रिप्ट में मैप किए गए प्रकार के लिए अनुक्रमणिका हस्ताक्षर
- मैं मैप किए गए प्रकार के लिए एक इंडेक्स हस्ताक्षर कैसे जोड़ूं
लेकिन लोग सीधे संबंधित नहीं थे, हालांकि एक समान नाम था।
जवाब
type HasKeyValue<K extends string, V> = { [s: string]: any } & { [S in K]: V }आपके द्वारा किए गए प्रकार को परिभाषित करने का सही तरीका है। लेकिन एक बात जानने की है ( चित्रण ध्वज चिह्नित करें: keyofStringsOnly ):
keyof प्रकार ऑपरेटर रिटर्न स्ट्रिंग | स्ट्रिंग के बजाय नंबर जब एक स्ट्रिंग इंडेक्स हस्ताक्षर के साथ एक प्रकार पर लागू होता है।
मुझे पता नहीं है कि इंडेक्स को केवल stringटाइप करने के लिए प्रतिबंधित करने का कोई तरीका है और नहीं string | number। वास्तव में इंडेक्स numberको एक्सेस करने की अनुमति देना stringएक उचित बात लगती है, क्योंकि यह लाइन में है कि कैसे जावास्क्रिप्ट काम करता है (कोई भी एक संख्या को हमेशा सख्त कर सकता है)। दूसरी ओर आप एक स्ट्रिंग मान के साथ संख्या सूचकांक तक सुरक्षित रूप से नहीं पहुंच सकते।
&प्रकार ऑपरेटर इसी तरह काम करता है सैद्धांतिक चौराहे सेट करने के लिए - यह हमेशा संभव मूल्यों का सेट प्रतिबंधित (या पत्ते उन्हें अपरिवर्तित, लेकिन कभी नहीं फैली)। आपके मामले में प्रकार किसी भी गैर-स्ट्रिंग जैसी कुंजियों को शामिल नहीं करता है। सटीक होने के लिए आप unique symbolसूचकांक के रूप में बाहर करते हैं।
मुझे लगता है कि आपका भ्रम इस प्रकार हो सकता है कि कैसे टाइपस्क्रिप्ट फ़ंक्शन मापदंडों का व्यवहार करता है। स्पष्ट रूप से परिभाषित मापदंडों के साथ एक फ़ंक्शन को कॉल करना वैरिएबल के रूप में गुजरने वाले मापदंडों से भिन्न व्यवहार करता है। दोनों मामलों में टाइपस्क्रिप्ट सुनिश्चित करता है कि सभी पैरामीटर सही संरचना / आकार के हैं, लेकिन बाद के मामले में यह अतिरिक्त रूप से अतिरिक्त प्रॉप्स की अनुमति नहीं देता है।
अवधारणाओं को दर्शाने वाला कोड:
type HasKeyValue<K extends string, V> = { [s: string]: any } & { [S in K]: V };
type WithNumber = HasKeyValue<"n", number>;
const x: WithNumber = {
n: 1
};
type T = keyof typeof x; // string | number
x[0] = 2; // ok - number is a string-like index
const s = Symbol("s");
x[s] = "2"; // error: cannot access via symbol
interface N {
n: number;
}
function fn(p: N) {
return p.n;
}
const p1 = {
n: 1
};
const p2 = {
n: 2,
s: "2"
};
fn(p1); // ok - exact match
fn(p2); // ok - structural matching: { n: number } present; additional props ignored
fn({ n: 0, s: "s" }); // error: additional props not ignore when called explictily
fn({}); // error: n is missing
संपादित करें
ऑब्जेक्ट शाब्दिक - स्पष्ट रूप से कुछ आकार की वस्तु बनाना जैसे const p: { a: number} = { a: 42 }कि टाइपस्क्रिप्ट द्वारा एक विशेष तरीके से व्यवहार किया जाता है। नियमित संरचनात्मक अनुमान के विपरीत, प्रकार को बिल्कुल मिलान किया जाना चाहिए। और ईमानदार होने के लिए यह समझ में आता है, उन अतिरिक्त गुणों के रूप में - अतिरिक्त संभवतः असुरक्षित कलाकारों के बिना - वैसे भी दुर्गम हैं।
[...] हालांकि, टाइपस्क्रिप्ट इस रुख में शायद एक बग है। ऑब्जेक्ट शाब्दिक रूप से विशेष उपचार प्राप्त करते हैं और अन्य चर को असाइन करते समय, या उन्हें तर्क के रूप में पारित करते हुए अतिरिक्त संपत्ति जांच से गुजरते हैं। यदि किसी ऑब्जेक्ट शाब्दिक में कोई गुण है जो "लक्ष्य प्रकार" के पास नहीं है, तो आपको एक त्रुटि मिलेगी। [...] इन चेकों के आसपास पहुंचने का एक अंतिम तरीका, जो थोड़ा आश्चर्यचकित करने वाला हो सकता है, वह वस्तु को किसी अन्य चर में निर्दिष्ट करना है।
टीएस हैंडबुक
इस त्रुटि के आसपास पाने के लिए अन्य विकल्प ... के साथ इसे काटना है { [prop: string]: any }।
अधिक कोड:
function f(x: { a: number }) {}
function g(y: { b: number }) {}
function h(z: { a: number } & { b: number }) {}
f({ a: 42, b: 58 } as { a: number }); // compiles - cast possible, but `b` inaccessible anyway
g({ a: 42 } as { b: number }); // does not compile - incorrect cast; Conversion of type '{ a: number; }' to type '{ b: number; }' may be a mistake
h({ a: 42, b: 58 }); // compiles!
const p = {
a: 42,
b: 58
};
f(p); // compiles - regular structural typing
g(p); // compiles - regular structural typing
h(p); // compiles - regular structural typing
const i: { a: number } = { a: 42, b: 58 }; // error: not exact match
f(i); // compiles
g(i); // error
h(i); // error
यहाँ चौराहे ऑपरेटर के बारे में तर्क करने का एक तरीका है। शायद यह मदद करता है:
type Intersection = { a: string } & { b: number }
आप पढ़ सकते हैं Intersection"के रूप में एक वस्तु एक संपत्ति है कि aप्रकार के string और एक संपत्ति bप्रकार के number"। यह इस सरल प्रकार का वर्णन करने के लिए भी होता है:
type Simple = { a: string; b: number }
और दो प्रकार संगत हैं। आप लगभग सभी उद्देश्यों के लिए एक को दूसरे के साथ बदल सकते हैं।
मुझे आशा है कि यह बताता है कि HasKeyValueवास्तव में उसी तरह क्यों है जिस प्रकार आप परिभाषित करने की कोशिश कर रहे थे।
जैसा कि क्यों T_key_and_indexकाम नहीं करता है, यह इसलिए है क्योंकि पहला भाग, [a in k]: Vएक मैप किए गए प्रकार को परिभाषित करता है , और एक मैप किए गए प्रकार की परिभाषा में आपके पास अतिरिक्त गुण नहीं हो सकते हैं। यदि आपको मैप किए गए प्रकार में अतिरिक्त गुण जोड़ने की आवश्यकता है, तो आप एक प्रकार का चौराहा& बना सकते हैं ।