I'm trying to figure out why getLabelForType works but getOtherLableForType fails typing:
export const things = {
THING1: 'THING1',
THING2: 'THING2',
}
export type Thing = $Keys<typeof things>
type Empty = 'empty type' & 'nothing there'
export default function unexpectedCase(impossible: Empty): void {
throw new Error(`Unexpected case ${impossible}`)
}
export function getLabelForType(thing: Thing): string {
switch (thing) {
case 'THING1':
return 'Thing 1'
case 'THING2':
return 'Thing 2'
default:
unexpectedCase(thing)
return ''
}
}
export function getOtherLabelForType(thing: Thing): string {
(things.THING1: Thing)
switch (thing) {
case things.THING1:
return 'Thing 1'
case things.THING1:
return 'Thing 2'
default:
unexpectedCase(thing)
return ''
}
}
See the tryflow working example
Related
//this won't work
rules.filter(rule => rule.type === 'redirect' && new RegExp(rule.rule).exec(pathname.slice(1)))
.map(rule => {
console.log('match');
const url = req.nextUrl.clone()
url.pathname = rule.destination
return NextResponse.redirect(url)
})
//this does work
for (let rule of rules) {
const regex: RegExp = new RegExp(rule.rule)
if(regex.exec(pathname.slice(1)) && rule.type === 'redirect') {
console.log('match');
const url = req.nextUrl.clone()
url.pathname = rule.destination
return NextResponse.redirect(url)
}
}
the middleware is already running well with de for loop
Reddit gave me the solution, I leave it here
A return statement inside map simply adds to the map output array.
A return statement in a for loop exits the function.
Next.js will redirect if a middleware returns NextResponse.redirect(), as you would if you used a for loop and return statement.
let result
rules.filter(rule => rule.type === 'redirect' && new RegExp(rule.rule).exec(pathname.slice(1)))
.map(rule => {
console.log('match');
url.pathname = rule.destination
result = NextResponse.redirect(url)
})
return result
Can reproduce this issue. We had to convert:
PRIVATE_ROUTES.forEach((route) => {
if (url.pathname.includes(route)) {
if (!authenticated) {
url.pathname = Routes.auth.signIn;
return NextResponse.redirect(url);
} else if (
req.cookies.get('auth-next-url') &&
url.pathname !== req.cookies.get('auth-next-url')
) {
url.pathname = req.cookies.get('auth-next-url')!;
return NextResponse.redirect(url);
}
}
});
To this:
for (let route of PRIVATE_ROUTES) {
if (url.pathname.includes(route)) {
if (!authenticated) {
url.pathname = Routes.auth.signIn;
return NextResponse.redirect(url);
} else if (
req.cookies.get('auth-next-url') &&
url.pathname !== req.cookies.get('auth-next-url')
) {
url.pathname = req.cookies.get('auth-next-url')!;
return NextResponse.redirect(url);
}
}
}
I have an array of objects (not primitives) called "streaks" on my state tree and I want to observe only the changes to that array, not simply emit the entire array every time it changes. When I try this using pairwise() I get two identical arrays every time, even though I thought pairwise() would join the previous version and the current version. Why is pairwise() sending two identical arrays? NOTE streaks[1] and streaks[0] are identical, so _.differenceBy() isn't finding any changes because the two arrays are the same.
import {from} from "rxjs";
import {map, pairwise} from "rxjs/operators";
import * as _ from 'lodash';
const state$ = from(store);
const streaks$ = state$.pipe(
map(state => state.streaks),
// distinctUntilChanged(), <-- i've tried this and nothing is output at all
pairwise(),
map(streaks => {
let diff = _.differenceBy(streaks[0], streaks[1], _.isEqual);
console.log('diff', diff); //<-- this is an empty array
return diff;
})
);
streaks$.subscribe((streaksArray) => {
console.log('STREAKS$ 0', streaksArray); //<-- this is never even hit
} );
I solved this issue by creating an distinctUntilChangedArray operator that uses a self written compareArray function
Create compare array function
const compareArray<T> = (first: T[], second: T[], comparator=: (obj: T, obj2: T) => boolean): boolean {
return (first.length === 0 && second.length === 0)
|| (first.length === second.length && first.every((value, index) => {
return comparator
? comparator(value, second[index])
: JSON.stringify(value) === JSON.stringify(second[index]);
}))
}
Maybe you find a better array comparator. This is just my personal implementation of it
Create distinctUntilChangedArray operator
const distinctUntilChangedArray<T> = (comparator?: (prev: T, curr: T) => boolean): MonoTypeOperatorFunction<T[]> {
return distinctUntilChanged((prev: T[], curr: T[]) => {
return compareArray(first, second, comparator);
}
}
Final usage
interface nonPrimitive {
id: number;
name: string;
}
const nonPrimitiveComparator = (prev: nonPrimitive, curr: nonPrimitive): boolean => {
return prev.id === curr.id && prev.name === curr.name;
}
const source$: Observable<nonPrimitive>;
const distinctedSource$ = source$.pipe(
distinctUntilChangedArray(nonPrimitiveComparator)
);
I'm trying to fix a problem from the code and don't understand why is not working.
Function:
export const monthlyKpiActions_disp = (threeMonthsBefore, currentDate) => {
console.log('kpppppppppppppppi')
return monthlyKpiActions.fetch({
filter: {
objectId,
interval: threeMonthsBefore + '/' + currentDate,
names: [
'ecostats_fuelusagetotal',
'ecostats_fuelrefmileage',
'ecostats_co2emission',
'tripstats_mileage',
'tripstats_drivingtime',
'optidrive_indicator_8'
].join(',')
},
forceUpdate: true,
resetState: false
})
}
redux
function mapDispatchToProps(dispatch) {
return {
monthlyKpiActions_func: (threeMonthsBefore, currentDate) => dispatch(monthlyKpiActions_disp(threeMonthsBefore, currentDate)),
}
}
calling the function
const currentDate = moment.utc().add(1, 'months').format(dateFormat)
const threeMonthsBefore = moment.utc().subtract(3, 'months').format(dateFormat)
{ () => this.props.monthlyKpiActions_func(threeMonthsBefore, currentDate) }
The problem is that never enters the function, any suggestions?
That's because you never call the action, this line
{ () => this.props.monthlyKpiActions_func(threeMonthsBefore, currentDate) }
Creates a block scope with an anonymous function which internally calls your action, but its never invoked (nor makes any sense in this context).
Just call the action:
this.props.monthlyKpiActions_func(threeMonthsBefore, currentDate)
For every instantiation of RemoteEntity, I get an error on the type parameter that This type is incompatible with empty, referencing the null value for value in newRemoteEntity:
export type RemoteEntity<T: Identifiable> = {
value: ?T;
error: ?Error;
// ...
}
export function newRemoteEntity(): RemoteEntity<*> {
return {
value: null, // error
error: null, // OK
// ...
}
}
If I instead declare value: ?Object, these errors go away (but then I get other errors related to the loss of my type bound). Am I missing something or is this Flowtype bug/quirk?
I found a workaround by making the fields optional (instead of required but with a maybe-type). However, it makes other code a little more complicated (since I have to check for nulls instead of just propagating them in object literals), so I would prefer having maybe-types work.
export type RemoteEntity<T: Identifiable> = {
value?: T;
error?: Error;
pendingAction: ?string;
// ...
}
export function newRemoteEntity(): RemoteEntity<*> {
return {
pendingAction: null,
// ...
}
}
export function requested<T: Identifiable>(
state: RemoteEntity<T>, action: string, id?: string): RemoteEntity<T> {
// Maybe-type version was more concise:
// return {
// state: id && state.value && state.value.id === id ? state.value : null,
// error: null,
// pendingAction: action,
// // ...
// }
const result: RemoteEntity<T> = {
pendingAction: action,
// ...
}
if (id && state.value && state.value.id === id) {
result.value = state.value
}
return result
}
I'm doing a very simple react+redux application where I've a reducer called goals and a container called GoalsContainer.
From App Container I call the action goal for load the initial goals from a local db(indexedDB)
dispatch(loadGoals(currentDate));
This call the loadGoals from the goals actions:
export function loadGoals(currentDate = new Date()){
return dispatch => {
var goals = getGoalsFromDB(normalizeDate(currentDate)); // with this I get an array from the db
dispatch(setLoadGoals(goals));
}
}
function setLoadGoals(goals) {
return {
type: types.LOAD_GOALS,
goals
};
}
And then in my reducer I've this:
export default function goals(state = [], action) {
switch(action.type) {
case types.LOAD_GOALS:
return action.goals; // here I set the state of the goal reducer with the array passed via action
default:
console.log('Im here');
return state;
}
}
and this is my GoalsContainer(read the comments in code):
class GoalsContainer extends React.Component {
render() {
if (this.props.goals != undefined) {
console.log('ok called the render'); // in chrome console shows it
console.log(this.props.goals); // in chrome console shows correctly the goals loaded
console.log(this.props.goals.length); // it say 2
if (this.props.goals.length > 0) { // here fails...
console.log('good');
console.log(this.props.goals);
var goalsView = <div>There are goals</div>
}
else {
console.log('why go here?'); // go here
console.log(this.props.goals);
var goalsView = <div>No goals</div>
}
} else {
var goalsView = <div>Undefined</div>
}
return (
<div id="goals-main">
{goalsView}
</div>
);
}
}
GoalsContainer.propTypes = propTypes;
function mapStateToProps(state) {
const { goals, environment } = state;
const { currentDate } = environment;
return {
goals,
currentDate
}
}
export default connect(mapStateToProps)(GoalsContainer);
The problem is that when it does the if check, it fails(like if there are 0 goals), but in chrome console show correctly the goals array...
Then if I force with some workaround the render(), all works correctly.
What I've done wrong ?
You didn't mention if you use https://github.com/gaearon/redux-thunk or not. To use reducer returning function you should definitely install it.
It's hard to follow all of the parts of your code from random gists. What happens if you change your GoalsContainer to be;
class GoalsContainer extends React.Component {
render() {
console.log(this.props.goals);
return (
<div id="goals-main">
{(this.props.goals.length >= 1)?<div>There are goals</div>:<div>Nope!</div>}
</div>
);
}
}
What gets logged to the console?