मेरे पास एक पुस्तकालय है जो निम्नलिखित के समान एक उपयोगिता प्रकार का निर्यात करता है:
type Action<Model extends object> = (data: State<Model>) => State<Model>;
यह उपयोगिता प्रकार आपको एक फ़ंक्शन घोषित करने की अनुमति देता है जो "कार्रवाई" के रूप में प्रदर्शन करेगा। यह एक सामान्य तर्क प्राप्त करता है Model
कि कार्रवाई के खिलाफ काम करेगा।
data
"कार्रवाई" का तर्क फिर एक और उपयोगिता प्रकार है कि मैं निर्यात के साथ लिखा गया;
type State<Model extends object> = Omit<Model, KeysOfType<Model, Action<any>>>;
State
उपयोगिता प्रकार मूल रूप से भेजे लेता Model
सामान्य और फिर एक नए प्रकार जहां सभी गुण है कि प्रकार के होते हैं बनाता है Action
हटा दिया गया है।
उदाहरण के लिए यहां ऊपर का एक बुनियादी उपयोगकर्ता भूमि कार्यान्वयन है;
interface MyModel {
counter: number;
increment: Action<Model>;
}
const myModel = {
counter: 0,
increment: (data) => {
data.counter; // Exists and typed as `number`
data.increment; // Does not exist, as stripped off by State utility
return data;
}
}
ऊपर बहुत अच्छा काम कर रहा है। 👍
हालाँकि, एक ऐसा मामला है जिससे मैं जूझ रहा हूँ, खासकर जब एक जेनेरिक मॉडल की परिभाषा को परिभाषित किया गया है, साथ ही जेनेरिक मॉडल के उदाहरणों का निर्माण करने के लिए एक फैक्ट्री फ़ंक्शन के साथ।
उदाहरण के लिए;
interface MyModel<T> {
value: T; // 👈 a generic property
doSomething: Action<MyModel<T>>;
}
function modelFactory<T>(value: T): MyModel<T> {
return {
value,
doSomething: data => {
data.value; // Does not exist 😭
data.doSomething; // Does not exist 👍
return data;
}
};
}
ऊपर के उदाहरण में, मैं data
तर्क को टाइप करने की अपेक्षा करता हूं जहां doSomething
कार्रवाई को हटा दिया गया है, और सामान्य value
संपत्ति अभी भी मौजूद है। हालांकि यह मामला नहीं है - value
संपत्ति को हमारी State
उपयोगिता द्वारा भी हटा दिया गया है ।
मेरा मानना है कि इसका कारण यह है कि T
किसी भी प्रकार के प्रतिबंधों के बिना यह सामान्य है / इस पर लागू होने वाली संकीर्णता, और इसलिए प्रकार प्रणाली यह तय करती है कि यह एक Action
प्रकार के साथ प्रतिच्छेद करती है और बाद में इसे data
तर्क प्रकार से हटा देती है ।
क्या इस प्रतिबंध के आसपास आने का कोई रास्ता है? मैंने कुछ शोध किया है और उम्मीद कर रहा था कि कुछ ऐसा तंत्र होगा जिसमें मैं यह बता सकता हूँ कि T
कोई भी एक को छोड़कर है Action
। यानी एक नकारात्मक प्रकार का प्रतिबंध।
कल्पना कीजिए:
function modelFactory<T extends any except Action<any>>(value: T): UserDefinedModel<T> {
लेकिन टाइपस्क्रिप्ट के लिए वह सुविधा मौजूद नहीं है।
क्या किसी को इस तरह से पता है कि मुझे यह काम करने के लिए मिल सकता है जैसा कि मुझे उम्मीद है?
यहाँ डिबगिंग की सहायता के लिए एक पूर्ण कोड स्निपेट है:
// Returns the keys of an object that match the given type(s)
type KeysOfType<A extends object, B> = {
[K in keyof A]-?: A[K] extends B ? K : never
}[keyof A];
// Filters out an object, removing any key/values that are of Action<any> type
type State<Model extends object> = Omit<Model, KeysOfType<Model, Action<any>>>;
// My utility function.
type Action<Model extends object> = (data: State<Model>) => State<Model>;
interface MyModel<T> {
value: T; // 👈 a generic property
doSomething: Action<MyModel<T>>;
}
function modelFactory<T>(value: T): MyModel<T> {
return {
value,
doSomething: data => {
data.value; // Does not exist 😭
data.doSomething; // Does not exist 👍
return data;
}
};
}
आप इस कोड उदाहरण के साथ यहां खेल सकते हैं: https://codesandbox.io/s/reverent-star-m4sdb?fontsize=14