मेरे पास एक पुस्तकालय है जो निम्नलिखित के समान एक उपयोगिता प्रकार का निर्यात करता है:
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