How to use nested arrays in props in vue3? - vuejs3

I'm using SFC and a setup script with Vue3 (and typescript), and I can't seem to create a prop that's a nested array:
const props = defineProps({
title: String,
desc: String,
columns: Array<Array<String>>,
});

The answer is in https://vuejs.org/api/sfc-script-setup.html#typescript-only-features
The syntax for typescript is different:
const props = defineProps<{
foo: string
bar?: number
}>()

I think that you would be looking at something like this.
const props = defineProps<{
title: string;
desc: string;
columns: string[][];
}>()
If you are using optional props I would also recommend looking at withDefaults.

Related

How to reuse composable props in vue 3

Essentially, i want to build input fields components (textfeids, textarea, checkbox, ...).
Since they share some attributes ie (id, name,...), my approach was to create a composable and defined the common prop definition and use them in the individual components. However, it seem it does work. Is there a way I can achieve this in vue 3 composable approach. Below is the composable.
// prop definition
import { defineProps } from "vue";
export const useCoreFieldProps = () => {
const props = defineProps<{
id?: string;
name?: string;
disabled?: boolean;
required?: boolean;
}>();
return {
props,
};
};
// composable usage
<script setup lang="ts">
import { useCoreFieldProps } from "#/composables/useFields";
const { props: coreProps } = useCoreFieldProps();
</script>
Rather than calling defineProps in the composable, you can return just the object and you can call defineProps on it in your component:
// composable definition
export const useCoreFieldProps = () => {
const fieldProps = {
id?: string;
name?: string;
disabled?: boolean;
required?: boolean;
};
return {
fieldProps,
};
};
// composable usage
<script setup lang="ts">
import { useCoreFieldProps } from "#/composables/useFields";
const { fieldProps } = useCoreFieldProps();
defineProps(fieldProps);
// or add your own props or override:
defineProps({
...fieldProps,
maxLength?: string,
pattern?: string
});
</script>
You will unfortunately lose automated documentation of props if you’re using storybook or similar component library browsing tools, but hopefully they'll add support for that soon.
The other option is extends, but the docs don’t really explain how that works in Vue 3 with composition.

Best way to type actions with Redux? (flowtype)

What is the best way to type actions with redux?
"Best" meaning maximize readability and simultaneously minimize work required to write/maintain.
e.g. for the file...
// #flow
export const incrementCounter = (counter: string, amount: number) => ({
type: 'INCREMENT_COUNTER',
counter,
amount
})
export const resetCounter = (counter: string) => ({
type: 'RESET_COUNTER',
counter
})
This is currently how I type my actions, it uses the $Call Utility Type.
// #flow
export const incrementCounter = (counter: string, amount: number) => ({
type: 'INCREMENT_COUNTER',
counter,
amount
})
export const resetCounter = (counter: string) => ({
type: 'RESET_COUNTER',
counter
})
export Action =
| $Call<typeof incrementCounter, *, *>
| $Call<typeof resetCounter, *>
If you split your actions into multiple files, you can then merge all the actions together in a top level index like so...
import type { Action as CounterActions } from './counter-actions'
import type { Action as TimerActions } from './timer-actions'
export type Action =
| CounterActions
| TimerActions

Flow doesn't complain with incompatible ReactClass usage and JSX

I believe the following should be caught by flow:
type MyProps = {
foo: boolean,
};
const makeComponent = (C: ReactClass<MyProps>) => <C />;
From reading the source, I believe I am understanding ReactClass correctly.
What gives? This seems to also work with React.createElement(C, {})
On the other hand, the following breaks:
import MyComponent from '...'; // this component has props MyProps
const makeComponent = () => <MyComponent />;
// and likewise with React.createElement
According to this comment, ReactClass is buggy at best and should not be used. You can use the following instead:
type MyProps = {
foo: boolean,
};
const makeComponent = (C: Class<React.Component<void, MyProps, void>>) => <C />;
Note that the parameters for React.Component are defaultProps, Props, and State. In the above example it is assumed that the component does not have either defaultProps or State defined, hence the void values.

flowtype how to get a list of function return values

I want to extract the props mapStateToProps is giving me, to add to my ownProps as the list of props the component is getting. This seems pretty usual for me, using react/redux with flow.
I can define my type manually:
type StateProps = {
activeDuration: ?number,
activeColor: ?number,
activeAccessories: ?number[],
}
const mapStateToProps = (state): StateProps => ({
activeDuration: getActiveDuration(state),
activeColor: getActiveColor(state),
activeAccessories: getActiveAccessories(state),
});
But all these getX functions already know their return type. So actually mapStateToProps already knows its return type...
But I can't use:
type Props = { defaultProp: boolean } & mapStateToProps;
because mapStateToProps is the function itself, not the return value.
The question is: how can I get (not set) a type of what a function will return.
The following code can extract a return type from a function type:
type _ExtractReturn<B, F: (...args: any[]) => B> = B;
type ExtractReturn<F> = _ExtractReturn<*, F>;
Let's use this:
const mapStateToProps = (state) => ({
activeDuration: getActiveDuration(state),
activeColor: getActiveColor(state),
activeAccessories: getActiveAccessories(state),
});
type StateProps = ExtractReturn<typeof mapStateToProps>
Here is alternative solution based on $ObjMap instead:
type ExtractReturn<F> =
$PropertyType<$ObjMap<{ x: F }, <R>(f: () => R) => R>, 'x'>

Reformatting initialValues in redux-form

I am loading the Redux form with initialValues being passed as props. However, I need to reformat the data so as to fit my form names .. so e.g if the data in initialValues passed as props is {name: 'John', age: '32'}, I want to convert it to {user: {name: 'John', age: '32'}}. How do you achieve it ? Do you write a reducer to accomplish this and if yes then how do you invoke it at the component load ?
Thanks.
You could just do it when you pass in the prop.
const userData = { name: 'John', age: 32 }
...
<MyForm initialValues={{ user: userData }}/>
If you need some bigger changes, you can also pass a function to initialValues:
const getInitialValues = (propValues) => {
const initialValues = {};
// your function to format the values here
return initialValues;
};
#reduxForm(
{
form: 'myForm',
fields: formFields,
},
state => ({
initialValues: getInitialValues(state.userData),
form: state.form
})
)

Resources