टाइपस्क्रिप्ट में एक निश्चित लंबाई ऐरे की घोषणा कैसे करें


105

टाइपस्क्रिप्ट प्रकार के आसपास के मेरे ज्ञान की कमी को प्रदर्शित करने के जोखिम में - मेरे पास निम्नलिखित प्रश्न हैं।

जब आप किसी सरणी के लिए इस तरह की घोषणा करते हैं ...

position: Array<number>;

... यह आपको मनमानी लंबाई के साथ एक सरणी बनाने देगा। हालाँकि, यदि आप x, y, z घटकों के लिए एक विशिष्ट लंबाई के साथ संख्या युक्त सरणी चाहते हैं, तो z घटक आप एक निश्चित लंबाई सरणी के लिए एक प्रकार बना सकते हैं, ऐसा कुछ?

position: Array<3>

किसी भी मदद या स्पष्टीकरण की सराहना की!

जवाबों:


165

जावास्क्रिप्ट सरणी में एक निर्माता होता है जो सरणी की लंबाई को स्वीकार करता है:

let arr = new Array<number>(3);
console.log(arr); // [undefined × 3]

हालाँकि, यह सिर्फ प्रारंभिक आकार है, इसे बदलने पर कोई प्रतिबंध नहीं है:

arr.push(5);
console.log(arr); // [undefined × 3, 5]

टाइपस्क्रिप्ट में टफल प्रकार होते हैं जो आपको एक सरणी को एक विशिष्ट लंबाई और प्रकारों के साथ परिभाषित करते हैं:

let arr: [number, number, number];

arr = [1, 2, 3]; // ok
arr = [1, 2]; // Type '[number, number]' is not assignable to type '[number, number, number]'
arr = [1, 2, "3"]; // Type '[number, number, string]' is not assignable to type '[number, number, number]'

18
टुपल प्रकार केवल प्रारंभिक आकार की जांच करता है, इसलिए आप arrइसे प्रारंभ करने के बाद भी असीमित संख्या को "संख्या" पर धकेल सकते हैं ।
बेंजामिन

4
यह सच है, यह उस समय "कुछ भी हो जाता है" रनटाइम पर जावास्क्रिप्ट है। कम से कम टाइपस्क्रिप्ट ट्रांसपिलर इसे स्रोत कोड में कम से कम लागू करेगा
henryJack

7
यदि मैं चाहता हूं कि बड़े सरणी आकार, जैसे, 50, क्या बार-बार प्रकार के साथ सरणी आकार निर्दिष्ट करने का एक तरीका है, जैसे [number[50]], ताकि [number, number, ... ]50 बार लिखना आवश्यक न हो ?
विक्टर ज़मानियन

2
कोई बात नहीं, इस संबंध में एक सवाल मिला। stackoverflow.com/questions/52489261/…
विक्टर ज़मोनियन

1
@VictorZamanian सिर्फ इसलिए कि आप जागरूक हैं, {length: TLength}किसी भी प्रकार की त्रुटि प्रदान करने का विचार आपको टाइप किए गए से अधिक नहीं देना चाहिए TLength। मुझे अभी तक आकार-लागू एन-लंबाई प्रकार सिंटैक्स नहीं मिला है।
लुकास मॉर्गन

23

टपल दृष्टिकोण:

यह समाधान ट्यूपल्स में स्थित एक सख्त फिक्स्डलिंकअरे (ak.a. SealedArray) प्रकार का हस्ताक्षर प्रदान करता है ।

सिंटेक्स उदाहरण:

// Array containing 3 strings
let foo : FixedLengthArray<[string, string, string]> 

यह सबसे सुरक्षित तरीका है, इस पर विचार करने से यह सूचकांक को सीमाओं से बाहर जाने से रोकता है

कार्यान्वयन:

type ArrayLengthMutationKeys = 'splice' | 'push' | 'pop' | 'shift' | 'unshift' | number
type ArrayItems<T extends Array<any>> = T extends Array<infer TItems> ? TItems : never
type FixedLengthArray<T extends any[]> =
  Pick<T, Exclude<keyof T, ArrayLengthMutationKeys>>
  & { [Symbol.iterator]: () => IterableIterator< ArrayItems<T> > }

टेस्ट:

var myFixedLengthArray: FixedLengthArray< [string, string, string]>

// Array declaration tests
myFixedLengthArray = [ 'a', 'b', 'c' ]  // ✅ OK
myFixedLengthArray = [ 'a', 'b', 123 ]  // ✅ TYPE ERROR
myFixedLengthArray = [ 'a' ]            // ✅ LENGTH ERROR
myFixedLengthArray = [ 'a', 'b' ]       // ✅ LENGTH ERROR

// Index assignment tests 
myFixedLengthArray[1] = 'foo'           // ✅ OK
myFixedLengthArray[1000] = 'foo'        // ✅ INVALID INDEX ERROR

// Methods that mutate array length
myFixedLengthArray.push('foo')          // ✅ MISSING METHOD ERROR
myFixedLengthArray.pop()                // ✅ MISSING METHOD ERROR

// Direct length manipulation
myFixedLengthArray.length = 123         // ✅ READ-ONLY ERROR

// Destructuring
var [ a ] = myFixedLengthArray          // ✅ OK
var [ a, b ] = myFixedLengthArray       // ✅ OK
var [ a, b, c ] = myFixedLengthArray    // ✅ OK
var [ a, b, c, d ] = myFixedLengthArray // ✅ INVALID INDEX ERROR

(*) इस समाधान के लिए कार्य करने के लिए noImplicitAnyटाइपस्क्रिप्ट कॉन्फ़िगरेशन निर्देश को सक्षम करने की आवश्यकता होती है (आमतौर पर अनुशंसित अभ्यास)


ऐरे (ईश) दृष्टिकोण:

यह समाधान Arrayएक अतिरिक्त दूसरे पैरामीटर (एरे लंबाई) को स्वीकार करते हुए, प्रकार की वृद्धि के रूप में व्यवहार करता है । टपल आधारित समाधान के समान सख्त और सुरक्षित नहीं है ।

सिंटेक्स उदाहरण:

let foo: FixedLengthArray<string, 3> 

ध्यान रखें कि यह दृष्टिकोण आपको घोषित सीमाओं से बाहर एक सूचकांक तक पहुंचने से रोक नहीं पाएगा और इस पर एक मूल्य निर्धारित करेगा।

कार्यान्वयन:

type ArrayLengthMutationKeys = 'splice' | 'push' | 'pop' | 'shift' |  'unshift'
type FixedLengthArray<T, L extends number, TObj = [T, ...Array<T>]> =
  Pick<TObj, Exclude<keyof TObj, ArrayLengthMutationKeys>>
  & {
    readonly length: L 
    [ I : number ] : T
    [Symbol.iterator]: () => IterableIterator<T>   
  }

टेस्ट:

var myFixedLengthArray: FixedLengthArray<string,3>

// Array declaration tests
myFixedLengthArray = [ 'a', 'b', 'c' ]  // ✅ OK
myFixedLengthArray = [ 'a', 'b', 123 ]  // ✅ TYPE ERROR
myFixedLengthArray = [ 'a' ]            // ✅ LENGTH ERROR
myFixedLengthArray = [ 'a', 'b' ]       // ✅ LENGTH ERROR

// Index assignment tests 
myFixedLengthArray[1] = 'foo'           // ✅ OK
myFixedLengthArray[1000] = 'foo'        // ❌ SHOULD FAIL

// Methods that mutate array length
myFixedLengthArray.push('foo')          // ✅ MISSING METHOD ERROR
myFixedLengthArray.pop()                // ✅ MISSING METHOD ERROR

// Direct length manipulation
myFixedLengthArray.length = 123         // ✅ READ-ONLY ERROR

// Destructuring
var [ a ] = myFixedLengthArray          // ✅ OK
var [ a, b ] = myFixedLengthArray       // ✅ OK
var [ a, b, c ] = myFixedLengthArray    // ✅ OK
var [ a, b, c, d ] = myFixedLengthArray // ❌ SHOULD FAIL

1
धन्यवाद! हालांकि, त्रुटि प्राप्त किए बिना सरणी का आकार बदलना अभी भी संभव है।
एडुआर्ड

1
var myStringsArray: FixedLengthArray<string, 2> = [ "a", "b" ] // LENGTH ERRORलगता है 2 यहाँ 3 होना चाहिए?
क्वर्टी

मैंने कार्यान्वयन को एक कठोर समाधान के साथ अद्यतन किया है जो सरणी लंबाई में परिवर्तन को रोकता है
कॉलिज

@colxi क्या यह संभव है कि एक कार्यान्वयन हो सकता है जो कि फिक्स्डलैंगएयर्रे से मैपिंग की अनुमति देता है और अन्य फिक्स्डेलमैरिअरे के लिए? मेरा क्या मतलब है इसका एक उदाहरण:const threeNumbers: FixedLengthArray<[number, number, number]> = [1, 2, 3]; const doubledThreeNumbers: FixedLengthArray<[number, number, number]> = threeNumbers.map((a: number): number => a * 2);
एलेक्स मैल्कम

@AlexMalcolm मैं डर mapअपने उत्पादन के लिए एक सामान्य सरणी हस्ताक्षर प्रदान करता है। अपने मामले सबसे अधिक संभावना एक में number[]प्रकार
colxi

6

वास्तव में, आप इसे वर्तमान टाइपस्क्रिप्ट के साथ प्राप्त कर सकते हैं:

type Grow<T, A extends Array<T>> = ((x: T, ...xs: A) => void) extends ((...a: infer X) => void) ? X : never;
type GrowToSize<T, A extends Array<T>, N extends number> = { 0: A, 1: GrowToSize<T, Grow<T, A>, N> }[A['length'] extends N ? 0 : 1];

export type FixedArray<T, N extends number> = GrowToSize<T, [], N>;

उदाहरण:

// OK
const fixedArr3: FixedArray<string, 3> = ['a', 'b', 'c'];

// Error:
// Type '[string, string, string]' is not assignable to type '[string, string]'.
//   Types of property 'length' are incompatible.
//     Type '3' is not assignable to type '2'.ts(2322)
const fixedArr2: FixedArray<string, 2> = ['a', 'b', 'c'];

// Error:
// Property '3' is missing in type '[string, string, string]' but required in type 
// '[string, string, string, string]'.ts(2741)
const fixedArr4: FixedArray<string, 4> = ['a', 'b', 'c'];

1
जब तत्वों की संख्या एक चर है तो मैं इसका उपयोग कैसे करूं? यदि मेरे पास संख्या के रूप में एन और संख्या के रूप में "संख्या" है, तो कॉन्स्ट अरेस्ट: फिक्स्डअरे <नंबर, एन> = एरे.फ्रॉम (नया एरियर (संख्या), (x, i) => i); मुझे देता है "टाइप तात्कालिकता अत्यधिक गहरा है और संभवतः अनंत है"।
मीका श्वाब

2
@MichaSchwab दुर्भाग्य से यह केवल अपेक्षाकृत छोटी संख्या के साथ काम करता है। अन्यथा यह "बहुत अधिक पुनरावृत्ति" बताता है। आपके मामले में भी यही बात लागू होती है। मैंने इसका पूरी तरह से परीक्षण नहीं किया :(;
टॉमस गावेल

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