flow-type equivalent to 'as const' assertion in typescript - flowtype

surprisingly enough couldn't find an answer for this in StackOverflow, is there an equivalent of typescript 'as const' assertion in flow?
const realyConstObj = {key1: 'val1', key2: 'val2'}
// current type that is being infered:
typeof realyConstObj // {|key1: string, key2: string|}
// desired type is: {key1: 'val1', key2: 'val2'}
// in typescript
const realyConstObj = {key1: 'val1', key2: 'val2'} as const // will give the deisired outcome
// in flow i have to do:
const realyConstObj:{key1: 'val1', key2: 'val2'} = {key1: 'val1', key2: 'val2'}
// quiet annoing... is there an alternative?
found an open proposal for this feature in flow repo, but this 2 year old any maybe something updated since then

Related

Redux middleware with configureStore: Next is not a function

I'm trying to add a custom middleware to my Redux (I'm using it with configureStore)
const reducer = {
layout: layout,
login: login,
companies: companies,
services: services,
platforms: platforms,
report: report,
users: users,
stats: stats,
version: version,
}
const logger = store => next => action => {
console.log('dispatching', action)
let result = next(action)
console.log('next state', store.getState())
return result
}
const store = configureStore({
reducer,
middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(logger())
});
But I get Uncaught TypeError: next is not a function
Cannot find a working example with configureStore.
The packages that I'm using are:
"react-redux": "^8.0.2",
"redux": "^4.2.0",
"redux-thunk": "^2.4.1",
Update #1
I followed hint of
as following
const reducer = {
layout: layout,
login: login,
companies: companies,
services: services,
platforms: platforms,
report: report,
users: users,
stats: stats,
version: version,
wizard: wizard,
}
const logger = store => next => action => {
console.log('dispatching', action)
let result = next(action)
console.log('next state', store.getState())
return result
}
const middlewareLogger = logger(store)(next)(action);
const store = configureStore({
reducer,
middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(middlewareLogger())
});
export default store;
but i get
src/reducers/index.js
Line 33:40: 'next' is not defined no-undef
Line 33:46: 'action' is not defined no-undef
One minute after, I found solution, thanks to this post: Why does it says that 'next' is not defined in redux middleware code. Is next method of middleware deprecated?
Error was I'm calling logger() instead of logger.
So, I did't pass any arguments to logger.
Final working code:
const store = configureStore({
reducer,
middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(logger)
});

TS2322: Type 'T' is not assignable to type 'never'

I'm porting some JS to TS and have a simple app state module which allows me to set a property for later retrieval. When the ts compiler reaches the line state[propertyName] = value; inside the setAppState function, it throws the following error
TS2322: Type 'T' is not assignable to type 'never'.
I searched for this error but none of the other answers seem to address this case where I'm setting an object property using bracket notation.
Here's my code...
export interface appState {
context: typeof cast.framework.CastReceiverContext,
senderId: string,
requestId: number,
sessionId: string,
}
const state: appState = {
context: null,
senderId: null,
requestId: null,
sessionId: null,
};
export const getAppState = (propertyName: keyof appState): keyof appState => {
return state[propertyName];
};
export const setAppState = <T>(propertyName: keyof appState, value: T): void => {
state[propertyName] = value;
};
I found another question here that showed the correct way to write the types in the function signatures for the generic getter and setter, which solves the problem. The following now compiles.
export const getAppState = <K extends keyof appState>(propertyName: K): appState[K] => {
return state[propertyName];
};
export const setAppState = <K extends keyof appState>(propertyName: K, value: appState[K]): void => {
state[propertyName] = value;
};

Getting this error "Invariant failed: A state mutation was detected inside a dispatch, in the path: todoReducer.1."

I tried everything like spread operator but nothing works.
Here is my reducer
//state is an array of objects.
const initialState = [
{taskName: "kkkkk", isEdit: false},
]
export const todoReducer = (state=initialState, action) =>{
switch(action.type){
case 'add' :
const temp=
{
taskName: action.payload.taskName,
isEdit: action.payload.isEdit
}
state.push(temp);
return {state}
default: return state
}
}
The error message indicates that you are using Redux Toolkit - that is very good. The problem is that you are not using createSlice or createReducer and outside of those, in Redux you are never allowed to assign something to old state properties with = or call something like .push as it would modify the existing state.
Use createSlice instead:
const initialState = [
{taskName: "kkkkk", isEdit: false},
]
const slice = createSlice({
name: 'todos',
reducers: {
add(state, action) {
state.push(action.payload)
}
}
})
export const todoReducer = slice.reducer;
// this exports the auto-generated `add` action creator.
export const { add } = slice.actions;
Since the tutorial you are currently following seems to be incorporating both modern and completely outdated practices, I would highly recommend you to read the official Redux Tutorial instead, which shows modern concepts.

redux error on the property 'type' while using middlewares

I'm trying to integrate a logger in my redux app, using the applyMiddleware api, but when I trigger an action I got this error:
Actions may not have an undefined "type" property. Have you misspelled a constant?
This is strange because all of my action creators returns objects with this format:
{ type : ..., payload : {...}}. And more, in the console of the browser the printed object has the property 'type'.
I set up the store in this way:
const logger = store => next => action => {
console.log(action);
return next(store, action);
}
const store = createStore(
reducer,
applyMiddleware(logger));
export default store;
I got stuck.

Best practice redux actions with flowtype?

I want to write redux with flowtype, but I have questions about how to do that.
Redux with Flowtype
type ActionType =
| 'A'
| 'B'
;
// A generic type conforming to Flux Standard Action
type ActionT<A, P> = {|
type: A,
payload?: P | Error,
error?: boolean,
meta?: mixed
|};
type Action =
| ActionT<'A', string>
| ActionT<'B', number>
;
const error: Error = new Error('wrong');
const info = { href: '...' };
// ---- valid actions with flowtype ----
const action1: Action = {type: 'A', payload: 'hello' };
const action2: Action = {type: 'A', payload: error, error: true }; // The 'payload' could be an error.
const action3: Action = {type: 'A', payload: 'hello', meta: info }; // We can have 'meta'.
// ---- invalid actions with flowtype ----
const actionNG1: Action = {type: 'C', payload: 'hello' }; // Wrong 'type' value. The type 'C' is not allowed.
const actionNG2: Action = {type: 'B', payload: 'hello' }; // Wrong value type of 'payload'. It should be a number.
const actionNG3: Action = {type: 'A', payload: 'hello', threshold: 3 }; // Extra property 'threshold' is not allowed. It should conform to type ActionT.
I use ActionType instead of constants to check the valid type values.
The type ActionT conforms Flux Standard Action to ensure the structure of Redux actions.
The type Action declares the concrete types for all actions that we'll use in our App.
Question 1: how to ensure the first type passed to ActionT would be the type of ActionType (or at least, should be a string type)?
For example, adding a new type 'C' in not allowed, because ActionType only accepts 'A' and 'B'.
type ActionType =
| 'A'
| 'B'
;
type Action =
| ActionT<'A', string>
| ActionT<'B', number>
| ActionT<'C', number> // Should Raise an error
;
Does it make sense?
Question 2: how to write the reducers (and thunk) with flowtype and Immutable.js?
I've written a buildReducer to bind to a initial state.
type Action =
| ActionT<'SELECT_COUNTRY', string>
;
const buildReducer = (initialState, reducerMap) =>
(state = initialState, action) => {
const reducer = reducerMap[action.type];
return (reducer) ? reducer(state, action) : state;
};
const initialState = Immutable.fromJS({
selectedCountry: 'US'
})
const reducers = {
['SELECT_COUNTRY']: (state, action) => {
// how to know the type of payload is string type?
// how to ensure that `state.set(...)` gets right type of the value for the key?
return state.set('selectedCountry', action.payload)
}
}
const appReducer = buildReducer(initialState, reducers)
How can I check the payload type in the reducers for action type SELECT_COUNTRY with flowtype ?
How can I apply the payload value to the immutable state with flowtype check?
To answer question 1, you can use bounded polymorphism
// A generic type conforming to Flux Standard Action
type ActionT<A: ActionType, P> = {|
type: A,
payload?: P | Error,
error?: boolean,
meta?: mixed
|};
Notice how we bound the generic parameter A to ActionType
To answer question 2, you have to make sure to pull in immutable-js types here: https://github.com/facebook/immutable-js/blob/master/type-definitions/immutable.js.flow and then type your reducer functions.

Resources