react-state-monad 1.0.16 → 1.0.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,268 +1,268 @@
1
- # React State Monad
2
-
3
- [![npm](https://img.shields.io/npm/v/react-state-monad)](https://www.npmjs.com/package/react-state-monad/)
4
- [![Build Status](https://img.shields.io/github/actions/workflow/status/alvmivan/react-state-monad/publish.yml?branch=main)](https://github.com/alvmivan/react-state-monad/releases/latest)
5
- [![License](https://img.shields.io/github/license/alvmivan/react-state-monad)](./LICENSE)
6
-
7
- A set of hooks to manage/transform/filter states with monads in React.
8
-
9
- ## Description
10
-
11
- `react-state-monad` provides a set of monadic state management utilities, specifically designed to work seamlessly with
12
- React's state hooks. It allows you to manage, transform, and filter states in a functional and declarative way using
13
- monads like `Maybe` and `Option`.
14
-
15
- This library leverages the power of monads to encapsulate state changes, enabling a cleaner, more predictable way to
16
- handle various state conditions in React.
17
-
18
- ## Features
19
-
20
- - Manage state using monads like `Maybe` and `Option`.
21
- - Simplify handling of undefined or null values in state.
22
- - Leverage functional programming patterns in React state management.
23
- - Support for TypeScript with full type definitions.
24
-
25
- ## Installation
26
-
27
- You can install `react-state-monad` using npm or yarn:
28
-
29
- ```bash
30
- npm install react-state-monad
31
- ```
32
-
33
- or
34
-
35
- ```bash
36
- yarn add react-state-monad
37
- ```
38
-
39
- ## Usage
40
-
41
- Here's an example of how you can use the hooks in your React components:
42
-
43
- ### `useStateObject<T>`
44
-
45
- This hook initializes a StateObject with the provided initial value. It uses React's useState hook to manage the
46
- internal state and returns a StateObject that represents the current state.
47
-
48
- Parameters: `initialState`: The initial value of the state. This value can be of any type, determined by the generic
49
- type `T`.
50
-
51
- Returns a `StateObject` of type `T` representing the initialized state. This `StateObject` is an instance
52
- of `ValidState`, which
53
- encapsulates the state value and provides a `setValue` function to update it.
54
-
55
- ### `useEmptyState<T>`
56
-
57
- This hook initializes a `StateObject` with an empty state. It is useful as a fallback when no valid state is available.
58
-
59
- Parameters: None.
60
-
61
- Returns a `StateObject` of type `T` representing an empty state. This `StateObject` is an instance of `EmptyState`,
62
- which encapsulates the absence of a state value.
63
-
64
- ### `useElementState<T>`
65
-
66
- This hook allows you to derive and update a specific element in an array within a `StateObject`. It is useful for
67
- managing state at a granular level within an array.
68
-
69
- Parameters:
70
-
71
- - `state`: The `StateObject` containing an array.
72
- - `index`: The index of the element to be derived.
73
-
74
- Returns a `StateObject` of type `T` representing the element at the given index. If the index is out of bounds or the
75
- state is empty, it returns an instance of `EmptyState`. Otherwise, it returns an instance of `ValidState`, which
76
- encapsulates the element value and provides a `setValue` function to update it.
77
-
78
- ### `useFieldState<TOriginal, TField>`
79
-
80
- This hook derives a field from the state object and creates a new `StateObject` for the field's value. It is useful for
81
- managing state at a granular level within an object.
82
-
83
- Parameters:
84
-
85
- - `state`: The `StateObject` containing the original state.
86
- - `field`: The field name to be derived from the state.
87
-
88
- Returns a `StateObject` of type `TField` representing the derived field. This `StateObject` is an instance
89
- of `ValidState`, which encapsulates the field value and provides a `setValue` function to update it.
90
-
91
- For example:
92
-
93
- ```jsx
94
- import React from 'react';
95
- import {useStateObject, useFieldState} from 'react-state-monad';
96
-
97
- const MyComponent = () => {
98
- const userState = useStateObject({
99
- name: 'John Doe',
100
- age: 30,
101
- });
102
-
103
- const nameState = useFieldState(userState, 'name');
104
- const ageState = useFieldState(userState, 'age');
105
-
106
- return (
107
- <div>
108
- <input
109
- type="text"
110
- value={nameState.value}
111
- onChange={(e) => nameState.value = e.target.value}
112
- />
113
- <input
114
- type="number"
115
- value={ageState.value}
116
- onChange={(e) => ageState.value = parseInt(e.target.value, 10)}
117
- />
118
- </div>
119
- );
120
- };
121
-
122
- export default MyComponent;
123
- ```
124
-
125
- ### `useRemapArray<T>`
126
-
127
- This hook maps each element in an array within a `StateObject` to a new `StateObject`, allowing for independent updates
128
- of each element while keeping the overall array state synchronized.
129
-
130
- Parameters:
131
-
132
- - `state`: The `StateObject` containing an array.
133
-
134
- Returns an array of new `StateObject`s, each representing an element in the original array. This allows individual
135
- updates while keeping the array state synchronized. If the state has no value, it returns an empty array.
136
-
137
-
138
- ### `useNullSafety<TOrigin>`
139
-
140
- This hook ensures a `StateObject` contains a defined, non-null value. If the `StateObject`'s value is `undefined` or `null`, it returns an `EmptyState`. Otherwise, it returns a `ValidState` with the value and a setter to update the value.
141
-
142
- Parameters:
143
-
144
- - `state`: The `StateObject` which may contain a value, `undefined`, or `null`.
145
-
146
- Returns a `StateObject` of type `TOrigin` representing the value if it is defined and non-null, otherwise an `EmptyState`.
147
-
148
-
149
-
150
-
151
-
152
-
153
- ### Complete Example
154
-
155
- Here's a more complete example demonstrating the usage of `useStateObject`, `useFieldState`, `useElementState`,
156
- and `useRemapArray` hooks in a React component:
157
-
158
- ```tsx
159
-
160
- const AgeField = (props: { ageState: StateObject<number> }) => <div>
161
- <label>Age:</label>
162
- <input
163
- type="number"
164
- value={props.ageState.value}
165
- onChange={x => props.ageState.value = parseInt(x.target.value, 10)}
166
- />
167
- </div>;
168
-
169
-
170
- const NameField = (props: { nameState: StateObject<string> }) => {
171
- return <div>
172
- <label>Name:</label>
173
- <input
174
- type="text"
175
- value={props.nameState.value}
176
- onChange={x => props.nameState.value = x.target.value}
177
- />
178
- </div>;
179
- }
180
-
181
- const HobbyField = (props: { hobbyState: StateObject<string> }) => {
182
- return <div>
183
- <input
184
- type="text"
185
- value={props.hobbyState.value}
186
- onChange={x => props.hobbyState.value = x.target.value}
187
- />
188
- </div>;
189
- }
190
-
191
- const HobbiesField = (props: { hobbiesState: StateObject<string[]> }) => {
192
-
193
- const hobbyStates: StateObject<string>[] = useRemapArray(props.hobbiesState);
194
-
195
- const addHobby = () => {
196
- // Always use the setter to update arrays, do not modify them directly to ensure React state consistency.
197
- // Immutability is key 💗
198
- props.hobbiesState.value = [...props.hobbiesState.value, ''];
199
- }
200
-
201
- return <div>
202
- <label>Hobbies:</label>
203
- {
204
- hobbyStates.map((hobbyState, index) => <HobbyField key={index} hobbyState={hobbyState}/>)
205
- }
206
- <button onClick={addHobby}>Add Hobby</button>
207
- </div>;
208
-
209
-
210
- };
211
-
212
- export const UserProfile = () => {
213
-
214
- type DudeData = {
215
- name: string;
216
- age: number;
217
- hobbies: string[];
218
- }
219
- // Initialize state with an object containing user details and an array of hobbies
220
- const userState: StateObject<DudeData> = useStateObject({
221
- name: 'John Doe',
222
- age: 30,
223
- hobbies: ['Reading', 'Traveling', 'Cooking'],
224
- });
225
-
226
- // Derive state for individual fields
227
- const nameState: StateObject<string> = useFieldState(userState, 'name');
228
- const ageState: StateObject<number> = useFieldState(userState, 'age');
229
-
230
- // Derive state for hobbies array
231
- const hobbiesState: StateObject<string[]> = useFieldState(userState, 'hobbies');
232
-
233
-
234
- return (
235
- <div>
236
- <h1>User Profile</h1>
237
- <NameField nameState={nameState}/>
238
- <AgeField ageState={ageState}/>
239
- <HobbiesField hobbiesState={hobbiesState}/>
240
- </div>
241
- );
242
- };
243
- ```
244
-
245
- ## Contributing
246
-
247
- Contributions are welcome! If you'd like to contribute to this library, please fork the repository and submit a pull
248
- request.
249
-
250
- How to Contribute
251
- Fork the repository.
252
-
253
- * Create a new branch for your feature `git checkout -b feature-name`
254
- * Commit your changes `git commit -am 'Add new feature'`
255
- * Push to the branch `git push origin feature-name`
256
- * Open a pull request. I'll be happy to review it!
257
-
258
- ## License
259
-
260
- This project is licensed under the GPL-3.0 License.
261
-
262
- ## Author
263
-
264
- `Marcos Alvarez`
265
-
266
- [<img src="https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png" width="38" height="38">](https://github.com/alvmivan)
267
- [<img src="https://www.linkedin.com/favicon.ico" width="40" height="40">](https://www.linkedin.com/in/marcos-alvarez-40651b150/)
1
+ # React State Monad
2
+
3
+ [![npm](https://img.shields.io/npm/v/react-state-monad)](https://www.npmjs.com/package/react-state-monad/)
4
+ [![Build Status](https://img.shields.io/github/actions/workflow/status/alvmivan/react-state-monad/publish.yml?branch=main)](https://github.com/alvmivan/react-state-monad/releases/latest)
5
+ [![License](https://img.shields.io/github/license/alvmivan/react-state-monad)](./LICENSE)
6
+
7
+ A set of hooks to manage/transform/filter states with monads in React.
8
+
9
+ ## Description
10
+
11
+ `react-state-monad` provides a set of monadic state management utilities, specifically designed to work seamlessly with
12
+ React's state hooks. It allows you to manage, transform, and filter states in a functional and declarative way using
13
+ monads like `Maybe` and `Option`.
14
+
15
+ This library leverages the power of monads to encapsulate state changes, enabling a cleaner, more predictable way to
16
+ handle various state conditions in React.
17
+
18
+ ## Features
19
+
20
+ - Manage state using monads like `Maybe` and `Option`.
21
+ - Simplify handling of undefined or null values in state.
22
+ - Leverage functional programming patterns in React state management.
23
+ - Support for TypeScript with full type definitions.
24
+
25
+ ## Installation
26
+
27
+ You can install `react-state-monad` using npm or yarn:
28
+
29
+ ```bash
30
+ npm install react-state-monad
31
+ ```
32
+
33
+ or
34
+
35
+ ```bash
36
+ yarn add react-state-monad
37
+ ```
38
+
39
+ ## Usage
40
+
41
+ Here's an example of how you can use the hooks in your React components:
42
+
43
+ ### `useStateObject<T>`
44
+
45
+ This hook initializes a StateObject with the provided initial value. It uses React's useState hook to manage the
46
+ internal state and returns a StateObject that represents the current state.
47
+
48
+ Parameters: `initialState`: The initial value of the state. This value can be of any type, determined by the generic
49
+ type `T`.
50
+
51
+ Returns a `StateObject` of type `T` representing the initialized state. This `StateObject` is an instance
52
+ of `ValidState`, which
53
+ encapsulates the state value and provides a `setValue` function to update it.
54
+
55
+ ### `useEmptyState<T>`
56
+
57
+ This hook initializes a `StateObject` with an empty state. It is useful as a fallback when no valid state is available.
58
+
59
+ Parameters: None.
60
+
61
+ Returns a `StateObject` of type `T` representing an empty state. This `StateObject` is an instance of `EmptyState`,
62
+ which encapsulates the absence of a state value.
63
+
64
+ ### `useElementState<T>`
65
+
66
+ This hook allows you to derive and update a specific element in an array within a `StateObject`. It is useful for
67
+ managing state at a granular level within an array.
68
+
69
+ Parameters:
70
+
71
+ - `state`: The `StateObject` containing an array.
72
+ - `index`: The index of the element to be derived.
73
+
74
+ Returns a `StateObject` of type `T` representing the element at the given index. If the index is out of bounds or the
75
+ state is empty, it returns an instance of `EmptyState`. Otherwise, it returns an instance of `ValidState`, which
76
+ encapsulates the element value and provides a `setValue` function to update it.
77
+
78
+ ### `useFieldState<TOriginal, TField>`
79
+
80
+ This hook derives a field from the state object and creates a new `StateObject` for the field's value. It is useful for
81
+ managing state at a granular level within an object.
82
+
83
+ Parameters:
84
+
85
+ - `state`: The `StateObject` containing the original state.
86
+ - `field`: The field name to be derived from the state.
87
+
88
+ Returns a `StateObject` of type `TField` representing the derived field. This `StateObject` is an instance
89
+ of `ValidState`, which encapsulates the field value and provides a `setValue` function to update it.
90
+
91
+ For example:
92
+
93
+ ```jsx
94
+ import React from 'react';
95
+ import {useStateObject, useFieldState} from 'react-state-monad';
96
+
97
+ const MyComponent = () => {
98
+ const userState = useStateObject({
99
+ name: 'John Doe',
100
+ age: 30,
101
+ });
102
+
103
+ const nameState = useFieldState(userState, 'name');
104
+ const ageState = useFieldState(userState, 'age');
105
+
106
+ return (
107
+ <div>
108
+ <input
109
+ type="text"
110
+ value={nameState.value}
111
+ onChange={(e) => nameState.value = e.target.value}
112
+ />
113
+ <input
114
+ type="number"
115
+ value={ageState.value}
116
+ onChange={(e) => ageState.value = parseInt(e.target.value, 10)}
117
+ />
118
+ </div>
119
+ );
120
+ };
121
+
122
+ export default MyComponent;
123
+ ```
124
+
125
+ ### `useRemapArray<T>`
126
+
127
+ This hook maps each element in an array within a `StateObject` to a new `StateObject`, allowing for independent updates
128
+ of each element while keeping the overall array state synchronized.
129
+
130
+ Parameters:
131
+
132
+ - `state`: The `StateObject` containing an array.
133
+
134
+ Returns an array of new `StateObject`s, each representing an element in the original array. This allows individual
135
+ updates while keeping the array state synchronized. If the state has no value, it returns an empty array.
136
+
137
+
138
+ ### `useNullSafety<TOrigin>`
139
+
140
+ This hook ensures a `StateObject` contains a defined, non-null value. If the `StateObject`'s value is `undefined` or `null`, it returns an `EmptyState`. Otherwise, it returns a `ValidState` with the value and a setter to update the value.
141
+
142
+ Parameters:
143
+
144
+ - `state`: The `StateObject` which may contain a value, `undefined`, or `null`.
145
+
146
+ Returns a `StateObject` of type `TOrigin` representing the value if it is defined and non-null, otherwise an `EmptyState`.
147
+
148
+
149
+
150
+
151
+
152
+
153
+ ### Complete Example
154
+
155
+ Here's a more complete example demonstrating the usage of `useStateObject`, `useFieldState`, `useElementState`,
156
+ and `useRemapArray` hooks in a React component:
157
+
158
+ ```tsx
159
+
160
+ const AgeField = (props: { ageState: StateObject<number> }) => <div>
161
+ <label>Age:</label>
162
+ <input
163
+ type="number"
164
+ value={props.ageState.value}
165
+ onChange={x => props.ageState.value = parseInt(x.target.value, 10)}
166
+ />
167
+ </div>;
168
+
169
+
170
+ const NameField = (props: { nameState: StateObject<string> }) => {
171
+ return <div>
172
+ <label>Name:</label>
173
+ <input
174
+ type="text"
175
+ value={props.nameState.value}
176
+ onChange={x => props.nameState.value = x.target.value}
177
+ />
178
+ </div>;
179
+ }
180
+
181
+ const HobbyField = (props: { hobbyState: StateObject<string> }) => {
182
+ return <div>
183
+ <input
184
+ type="text"
185
+ value={props.hobbyState.value}
186
+ onChange={x => props.hobbyState.value = x.target.value}
187
+ />
188
+ </div>;
189
+ }
190
+
191
+ const HobbiesField = (props: { hobbiesState: StateObject<string[]> }) => {
192
+
193
+ const hobbyStates: StateObject<string>[] = useRemapArray(props.hobbiesState);
194
+
195
+ const addHobby = () => {
196
+ // Always use the setter to update arrays, do not modify them directly to ensure React state consistency.
197
+ // Immutability is key 💗
198
+ props.hobbiesState.value = [...props.hobbiesState.value, ''];
199
+ }
200
+
201
+ return <div>
202
+ <label>Hobbies:</label>
203
+ {
204
+ hobbyStates.map((hobbyState, index) => <HobbyField key={index} hobbyState={hobbyState}/>)
205
+ }
206
+ <button onClick={addHobby}>Add Hobby</button>
207
+ </div>;
208
+
209
+
210
+ };
211
+
212
+ export const UserProfile = () => {
213
+
214
+ type DudeData = {
215
+ name: string;
216
+ age: number;
217
+ hobbies: string[];
218
+ }
219
+ // Initialize state with an object containing user details and an array of hobbies
220
+ const userState: StateObject<DudeData> = useStateObject({
221
+ name: 'John Doe',
222
+ age: 30,
223
+ hobbies: ['Reading', 'Traveling', 'Cooking'],
224
+ });
225
+
226
+ // Derive state for individual fields
227
+ const nameState: StateObject<string> = useFieldState(userState, 'name');
228
+ const ageState: StateObject<number> = useFieldState(userState, 'age');
229
+
230
+ // Derive state for hobbies array
231
+ const hobbiesState: StateObject<string[]> = useFieldState(userState, 'hobbies');
232
+
233
+
234
+ return (
235
+ <div>
236
+ <h1>User Profile</h1>
237
+ <NameField nameState={nameState}/>
238
+ <AgeField ageState={ageState}/>
239
+ <HobbiesField hobbiesState={hobbiesState}/>
240
+ </div>
241
+ );
242
+ };
243
+ ```
244
+
245
+ ## Contributing
246
+
247
+ Contributions are welcome! If you'd like to contribute to this library, please fork the repository and submit a pull
248
+ request.
249
+
250
+ How to Contribute
251
+ Fork the repository.
252
+
253
+ * Create a new branch for your feature `git checkout -b feature-name`
254
+ * Commit your changes `git commit -am 'Add new feature'`
255
+ * Push to the branch `git push origin feature-name`
256
+ * Open a pull request. I'll be happy to review it!
257
+
258
+ ## License
259
+
260
+ This project is licensed under the GPL-3.0 License.
261
+
262
+ ## Author
263
+
264
+ `Marcos Alvarez`
265
+
266
+ [<img src="https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png" width="38" height="38">](https://github.com/alvmivan)
267
+ [<img src="https://www.linkedin.com/favicon.ico" width="40" height="40">](https://www.linkedin.com/in/marcos-alvarez-40651b150/)
268
268
  [<img src="https://ssl.gstatic.com/ui/v1/icons/mail/rfr/gmail.ico" width="40" height="40">](mailto:alvmivan@gmail.com)
package/dist/index.cjs CHANGED
@@ -25,6 +25,7 @@ __export(index_exports, {
25
25
  useElementState: () => useElementState,
26
26
  useEmptyState: () => useEmptyState,
27
27
  useFieldState: () => useFieldState,
28
+ useNullSafety: () => useNullSafety,
28
29
  useRemapArray: () => useRemapArray,
29
30
  useStateObject: () => useStateObject
30
31
  });
@@ -156,6 +157,14 @@ function useArrayState(states) {
156
157
  return useStateObject(states.filter((state) => state.hasValue).map((state) => state.value));
157
158
  }
158
159
 
160
+ // src/hooks/useNullSafety.ts
161
+ function useNullSafety(state) {
162
+ if (!state.hasValue) return new EmptyState();
163
+ if (state.value === void 0) return new EmptyState();
164
+ if (state.value === null) return new EmptyState();
165
+ return new ValidState(state.value, (value) => state.value = value);
166
+ }
167
+
159
168
  // src/index.ts
160
169
  var index_default = void 0;
161
170
  // Annotate the CommonJS export names for ESM import in node:
@@ -164,6 +173,7 @@ var index_default = void 0;
164
173
  useElementState,
165
174
  useEmptyState,
166
175
  useFieldState,
176
+ useNullSafety,
167
177
  useRemapArray,
168
178
  useStateObject
169
179
  });
package/dist/index.d.cts CHANGED
@@ -127,6 +127,18 @@ declare function useArrayState<T>(states: StateObject<T>[]): StateObject<T[]>;
127
127
  */
128
128
  declare function useStateObject<T>(initialState: T): StateObject<T>;
129
129
 
130
+ /**
131
+ * Hook that ensures a StateObject contains a defined, non-null value.
132
+ * If the StateObject's value is `undefined` or `null`, it returns an EmptyState.
133
+ * Otherwise, it returns a ValidState with the value and a setter to update the value.
134
+ *
135
+ * @template TOrigin - The type of the value contained in the StateObject.
136
+ * @param state - The StateObject which may contain a value, `undefined`, or `null`.
137
+ * @returns A new StateObject containing the value if it is defined and non-null,
138
+ * otherwise an EmptyState.
139
+ */
140
+ declare function useNullSafety<TOrigin>(state: StateObject<TOrigin | undefined | null>): StateObject<TOrigin>;
141
+
130
142
  declare const _default: undefined;
131
143
 
132
- export { type StateObject, _default as default, useArrayState, useElementState, useEmptyState, useFieldState, useRemapArray, useStateObject };
144
+ export { type StateObject, _default as default, useArrayState, useElementState, useEmptyState, useFieldState, useNullSafety, useRemapArray, useStateObject };
package/dist/index.d.ts CHANGED
@@ -127,6 +127,18 @@ declare function useArrayState<T>(states: StateObject<T>[]): StateObject<T[]>;
127
127
  */
128
128
  declare function useStateObject<T>(initialState: T): StateObject<T>;
129
129
 
130
+ /**
131
+ * Hook that ensures a StateObject contains a defined, non-null value.
132
+ * If the StateObject's value is `undefined` or `null`, it returns an EmptyState.
133
+ * Otherwise, it returns a ValidState with the value and a setter to update the value.
134
+ *
135
+ * @template TOrigin - The type of the value contained in the StateObject.
136
+ * @param state - The StateObject which may contain a value, `undefined`, or `null`.
137
+ * @returns A new StateObject containing the value if it is defined and non-null,
138
+ * otherwise an EmptyState.
139
+ */
140
+ declare function useNullSafety<TOrigin>(state: StateObject<TOrigin | undefined | null>): StateObject<TOrigin>;
141
+
130
142
  declare const _default: undefined;
131
143
 
132
- export { type StateObject, _default as default, useArrayState, useElementState, useEmptyState, useFieldState, useRemapArray, useStateObject };
144
+ export { type StateObject, _default as default, useArrayState, useElementState, useEmptyState, useFieldState, useNullSafety, useRemapArray, useStateObject };
package/dist/index.js CHANGED
@@ -124,6 +124,14 @@ function useArrayState(states) {
124
124
  return useStateObject(states.filter((state) => state.hasValue).map((state) => state.value));
125
125
  }
126
126
 
127
+ // src/hooks/useNullSafety.ts
128
+ function useNullSafety(state) {
129
+ if (!state.hasValue) return new EmptyState();
130
+ if (state.value === void 0) return new EmptyState();
131
+ if (state.value === null) return new EmptyState();
132
+ return new ValidState(state.value, (value) => state.value = value);
133
+ }
134
+
127
135
  // src/index.ts
128
136
  var index_default = void 0;
129
137
  export {
@@ -132,6 +140,7 @@ export {
132
140
  useElementState,
133
141
  useEmptyState,
134
142
  useFieldState,
143
+ useNullSafety,
135
144
  useRemapArray,
136
145
  useStateObject
137
146
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "react-state-monad",
3
3
  "type": "module",
4
- "version": "1.0.16",
4
+ "version": "1.0.17",
5
5
  "description": "A set of hooks to manage/transform/filter states with monads in React",
6
6
  "keywords": [
7
7
  "maybe",
@@ -1,12 +1,12 @@
1
- /**
2
- * Helper type that ensures a field is a valid key of an object and that the field's type matches the expected type.
3
- *
4
- * @template TObject - The object type.
5
- * @template TField - The expected type of the field.
6
- */
7
- export type ValidFieldFrom<TObject, TField> = {
8
- [Key in keyof TObject]: TObject[Key] extends TField ? Key : never;
9
- }[keyof TObject];
10
-
11
-
12
-
1
+ /**
2
+ * Helper type that ensures a field is a valid key of an object and that the field's type matches the expected type.
3
+ *
4
+ * @template TObject - The object type.
5
+ * @template TField - The expected type of the field.
6
+ */
7
+ export type ValidFieldFrom<TObject, TField> = {
8
+ [Key in keyof TObject]: TObject[Key] extends TField ? Key : never;
9
+ }[keyof TObject];
10
+
11
+
12
+