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

शायद यह कोड के साथ सबसे अच्छा समझाया गया है। यहां एक पुस्तकालय है जो कुछ बाकी एपीआई को सारणीबद्ध करता है:

interface RequestInterface {
  endpoint: string
  body?: unknown
}

interface GetPosts extends RequestInterface {
  endpoint: '/posts'
  body: never
}

interface CreatePost extends RequestInterface {
  endpoint: '/posts'
  body: string
}

function Factory<R extends RequestInterface> (endpoint: R['endpoint']) {

  return (body?: R['body']): void => {

    console.log(`Hitting ${endpoint} with ${body}`)

  }
}

const myLibrary = {

  getPosts: Factory<GetPosts>('/posts'),
  createPosts: Factory<CreatePost>('/posts'),

}

myLibrary.getPosts('something') // => Correctly errors
myLibrary.createPosts(999)      // => Correctly errors
myLibrary.createPosts()         // => I want this to error

उपरोक्त में, मैं अपने इंटरफेस में एक विशेष प्रकार के अनुरोध के endpoint और body को परिभाषित कर रहा हूं। हालांकि टाइपस्क्रिप्ट कंपाइलर गलत तर्क प्रकारों को पारित करने के खिलाफ सही ढंग से मेरी रक्षा करता है, यह किसी की आवश्यकता होने पर मान पारित नहीं करने के खिलाफ मेरी रक्षा नहीं करता है।

मैं समझता हूं कि टाइपस्क्रिप्ट त्रुटि क्यों नहीं करता है (क्योंकि कारखाने में परिभाषित विधि कैन मेरी टाइपिंग के अनुसार अपरिभाषित हो सकती है), लेकिन मुझे लगा कि उपरोक्त कोड वर्णन करने का एक अच्छा तरीका था मैं क्या हासिल करना चाहता हूं: विधियों की एक त्वरित, घोषणात्मक पुस्तकालय जो एक विशेष प्रकार को संतुष्ट करता है।

एक संभावित समाधान

अगर मैं अपने इंटरफेस को दो अलग-अलग इंटरफेस (एक या दूसरे) से विस्तारित करना चाहता हूं तो मैं हस्ताक्षर बनाएं:

interface RequestInterface {
  endpoint: string
  call: () => void
}

interface RequestInterfaceWithBody {
  endpoint: string
  call: {
    (body: any): void
  }
}

interface GetPosts extends RequestInterface {
  endpoint: '/posts'
}

interface CreatePost extends RequestInterfaceWithBody {
  endpoint: '/posts'
  call: {
    (body: string): void
  }
}

function Factory<R extends RequestInterface|RequestInterfaceWithBody> (endpoint: R['endpoint']): R['call'] {

  return (body): void => {

    console.log(`Hitting ${endpoint} with ${body}`)

  }
}

const myLibrary = {

  getPosts: Factory<GetPosts>('/posts'),
  createPosts: Factory<CreatePost>('/posts'),

}

myLibrary.getPosts()            // => Correctly passes
myLibrary.getPosts('something') // => Correctly errors
myLibrary.createPosts(999)      // => Correctly errors
myLibrary.createPosts()         // => Correctly errors
myLibrary.createPosts('hi')     // => Correctly passes

इस तथ्य के अलावा कि मुझे कुछ भी विस्तारित करने से पहले दो "सुपर" प्रकारों के बीच चयन करने की आवश्यकता है, इसके साथ एक बड़ी समस्या यह है कि निर्माण हस्ताक्षर तर्क बहुत सुलभ नहीं है।

हालांकि उदाहरण में प्रदर्शित नहीं किया गया है, मेरे द्वारा बनाए गए प्रकारों का उपयोग मेरे कोडबेस में कहीं और भी किया जाता है, और body पहुंच योग्य है (यानी GetPosts['body'])। उपर्युक्त के साथ, इसे एक्सेस करना आसान नहीं है और मुझे एक ही चीज़ प्राप्त करने के लिए शायद एक अलग पुन: उपयोग योग्य प्रकार परिभाषा बनाने की आवश्यकता होगी।

0
shennan 27 नवम्बर 2021, 12:06
डाउनवोट का कोई विशेष कारण?
 – 
shennan
27 नवम्बर 2021, 12:19
क्या आपके पास टाइपस्क्रिप्ट सख्त मोड सक्षम है? आप tsconfig.ts में "सख्त" विकल्प को सही पर सेट करके कर सकते हैं।
 – 
Jesse Schokker
27 नवम्बर 2021, 12:19

1 उत्तर

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

आपने अपने शुरुआती प्रकारों के साथ लगभग सही जगह पर पहुंच गया है। दो परिवर्तन आवश्यक:

  1. body का GetPosts प्रकार का void बनाएं
  2. body लौटाए गए फ़ंक्शन को आवश्यक बनाएं
interface RequestInterface {
  endpoint: string;
  body?: unknown;
}

interface GetPosts extends RequestInterface {
  endpoint: "/posts";
  body: void;
}

interface CreatePost extends RequestInterface {
  endpoint: "/posts";
  body: string;
}

function Factory<R extends RequestInterface>(endpoint: R["endpoint"]) {
  return (body: R["body"]): void => {
    console.log(`Hitting ${endpoint} with ${body}`);
  };
}

const myLibrary = {
  getPosts: Factory<GetPosts>("/posts"),
  createPosts: Factory<CreatePost>("/posts"),
};

// @ts-expect-error
myLibrary.getPosts("something");
// @ts-expect-error
myLibrary.createPosts(999);
// @ts-expect-error
myLibrary.createPosts();

myLibrary.getPosts();
myLibrary.createPosts("Hello, StackOverflow!");

टीएस खेल का मैदान

व्याख्या

never टाइप कंपाइलर को बताता है कि ऐसा कभी नहीं होना चाहिए। तो, यह कोई GetPosts का उपयोग करने का प्रयास करता है, यह एक त्रुटि है, क्योंकि ऐसा कभी नहीं होना चाहिए। void (undefined इस मामले में भी ठीक होना चाहिए) बताता है कि मान नहीं होना चाहिए।

लौटाए गए फ़ंक्शन में body आवश्यक बनाना आवश्यक बनाता है। लेकिन चूंकि यह GetPosts के लिए void है, आप इसे myLibrary.getPosts(undefined) या बस myLibrary.getPosts() की तरह कह सकते हैं, जो इसके बराबर है

0
Mr. Hedgehog 27 नवम्बर 2021, 13:17
शुक्रिया! टाइपस्क्रिप्ट के बारे में लोगों के ज्ञान और भाषा के कवरेज से मैं अब भी विनम्र हूं।
 – 
shennan
27 नवम्बर 2021, 13:18
सच कहूं तो, मैं टाइपस्क्रिप्ट को अच्छी तरह से नहीं जानता। मैंने आपके कोड को खेल के मैदान में कॉपी किया और जब तक यह काम नहीं करता तब तक इसके साथ खिलवाड़ किया। तभी मुझे समझ में आया कि क्यों इसने काम किया और क्या गलत था। जो कुछ बचा है - अपने कोड को एक बार फिर से कॉपी करें और उसमें प्रासंगिक भागों को लागू करें, इसलिए यह बहुत अलग नहीं होगा।
 – 
Mr. Hedgehog
27 नवम्बर 2021, 13:23
तो मैं आपको कम से कम आपकी ईमानदारी और तप के लिए बधाई देता हूं!
 – 
shennan
27 नवम्बर 2021, 13:30