Using ClassNameMap or Record<string,string> type for passing styles from one component to another - react-hooks

I am trying to pass more than one class styles from one component to another.
From Component A I am doing this,
const useStyles = makeStyles(() =>
createStyles({
label:{
width: "100%",
height: "100%",
margin: "10px",
backgroundColor: "white",
},
flex:{
}
})
);
const styles=useStyles();
const getAllList=labelNames.map((name: string):ReactNode => {
return (<Load
label={name}
classes={styles.flex} //here showing error under classes as "Type 'string' is not assignable to type 'ClassNameMap<string> | undefined'."
width={"100%"}
onDataChange={(value: string, data: string): void => {
}}
/>);
});
In Load component I declared like below,
interface Props {
width: string;
label: string;
classes?: ClassNameMap;
onDataChange: (selectedvalue: string, data: string) => void;
}
"Type 'string' is not assignable to type 'ClassNameMap | undefined'."
above error I am getting in the line which I mentioned above. I am unable to find what need to do to fix the error. Any idea or suggestions will help me to resolve. Anyone have any idea about how to pass class styles to specific component.
Also, I need to pass more than one style as props.

ClassNameMap and Record<string, string> are essentially the same. Both are objects whose keys are strings and whose values are string class names. If you want to refine the keys to just the allowed class names, ClassNameMap<‘label’ | ‘flex’> is the same as Record<‘label’ | ‘flex’, string>.
That’s not your issue. Your problem is that the Load component expects an object of class names, but you are providing it with a single string class name styles.flex. That’s why you get the error message:
Type 'string' is not assignable to type 'ClassNameMap | undefined'.
Based on what you are saying here:
I need to pass more than one style as props
Probably you want to pass the entire object that you got from the useStyles hook. Pass classes={styles} instead of classes={styles.flex}.

Related

How to destructure form input values from useFormikContext?

I am trying to destructure values to get specific value of the form inputs using useFormikContext()
I have done like:
const { values } = useFormikContext()
const { name, age } = values
but I'm getting error like:
Property 'name' does not exist on type 'unknown'
Fixed it.
I'm using typescript, when I added the interface to the useFormikContext() the error was gone.
Did it like this: useFormikContext<ProfileFields>()

How to trigger visitInputObject method on custom directive?

I'm building a custom directive in which I'm hoping to validate entire input objects. I'm using the INPUT_OBJECT type with the visitInputObject method on SchemaDirectiveVisitor extended class.
Every time I run a mutation using the input type then visitInputObject does not run.
I've used the other types/methods like visitObject and visitFieldDefinition and they work perfectly. But when trying to use input types and methods they will not trigger.
I've read all the available documentation I can find. Is this just not supported yet?
Some context code(Not actual):
directive #validateThis on INPUT_OBJECT
input MyInputType #validateThis {
id: ID
someField: String
}
type Mutation {
someMutation(myInput: MyInputType!): SomeType
}
class ValidateThisDirective extends SchemaDirectiveVisitor {
visitInputObject(type) {
console.log('Not triggering');
}
}
All the visit methods of a SchemaDirectiveVisitor are ran at the same time -- when the schema is built. That includes visitFieldDefinition and visitFieldDefinition. The difference is that when we use visitFieldDefinition, we often do it to modify the resolve function for the visited field. It's this function that's called during execution.
You use each visit methods to modify the respective schema element. You can use visitInputObject to modify an input object, for example to add or remove fields from it. You cannot use it to modify the resolution logic of an output object's field. You should use visitFieldDefinition for that.
visitFieldDefinition(field, details) {
const { resolve = defaultFieldResolver } = field
field.resolve = async function (parent, args, context, info) {
Object.keys(args).forEach(argName => {
const argDefinition = field.args.find(a => a.name === argName)
// Note: you may have to "unwrap" the type if it's a list or non-null
const argType = argDefinition.type
if (argType.name === 'InputTypeToValidate') {
const argValue = args[argName]
// validate here
}
})
return resolve.apply(this, [parent, args, context, info]);
}
}

Unable to access object property except by stringify/parse before the data in Graphql/resolver context

Unable to access my resolver returned object, however, I can see its content, but accessing properties returns an undefined. Only solution I found is using Stringify/Parse on my value.
Using JSON Stringify then PARSE on my Object turns it to be readable, but this is a lame solution :)
const MonkeyResolver = {
Monkey: {
address: (data, args, context) => {
console.log({data}); // Returns the actual entire object (monkey>address)
console.log(data.address); // --> Returns undefined
const newData = JSON.stringify(data);
const parsedData = JSON.parse(newData);
console.log(data.address); // --> Returns the address
}
}
}
My expected object is such as :
Object(monkey)
address:
city
street
What did I misunderstand?
Solved : if the reference database model schema manager does not include the properties, graphql prevent using the properties. I had to check out my defined schemas and solved by adding the needed object properties.

What and How does Relay and GraphQL interfaces work?

we define a type in GraphQL like this:
const GraphQLTodo = new GraphQLObjectType({
name: 'Todo',
fields: {
id: globalIdField('Todo'),
text: {
type: GraphQLString,
resolve: (obj) => obj.text,
},
complete: {
type: GraphQLBoolean,
resolve: (obj) => obj.complete,
},
},
interfaces: [nodeInterface], // what is this?
});
and I've read there is GraphQLInterfaceType - is more suitable when the types are basically the same but some of the fields are different(is this something like a foreign key?)
and in Relay we get the nodefield and nodeInterface with nodeDefinitions:
const {nodeInterface, nodeField} = nodeDefinitions(
(globalId) => {
const {type, id} = fromGlobalId(globalId);
if (type === 'Todo') {
return getTodo(id);
} else if (type === 'User') {
return getUser(id);
}
return null;
},
(obj) => {
if (obj instanceof Todo) {
return GraphQLTodo;
} else if (obj instanceof User) {
return GraphQLUser;
}
return null;
}
);
The docs and samples only used one on interfaces: [] //it's an array. but when do I need to use many interfaces? I am just confused on what it is, I've read a lot about it(don't know if my understanding is correct), just can't seem to wrap it in my head
A GraphQLInterfaceType is one way GraphQL achieves polymorphism, i.e. types that consist of multiple object types. For example, suppose you have two base object types, Post and Comment. Suppose you want a field that could get a list of both comments and posts. Conveniently, both these types have an id, text, and author field. This is the perfect use case for an interface type. An interface type is a group of shared fields, and it can be implemented by any object type which possesses those fields. So we create an Authored interface and say the Comment and Post implement this interface. By placing this Authored type on a GraphQL field, that field can resolve either posts or comments (or a heterogeneous list of both types).
But wait, Post and Comment accept an array of interfaces. I could pass multiple interfaces here. Why? Since the requirement for implementing an interface is possession of all the fields in that interface, there is no reason why any object type can't implement multiple interfaces. To draw from your example, the Node interface in Relay only needs id. Since our Post and Comment have id, they could implement both Node and Authored. But many other types will likely implement Node, ones that aren't part of Authored.
This makes your object types much more re-usable. If you assign interfaces to your field instead of object types, you can easily add new possible types to the fields in your schema as long as you stick to these agreed-upon interfaces.

TypeScript method type signature redundant

Maybe I'm seriously missing something, but I'm unable to get rid of a syntax problem with all my classes.
Here is an example :
class Foo {
bar: (x: string, y: number) => string = (xx: string, yy: number) : string => {
// do some stuff...
};
}
Since I'm enforcing type declarations using tslint, ALL my methods are written like this. It's horrible. Having to copy paste the arguments part, renaming the args names between the type declaration and the lambda declaration is soooo painfull.
So : is there a better way to combine type signature and lambda declaration without all the knee jerking ? I sincerely hope I have missed something and hope this is not "by design" ! :)
You need to configure TSLint to enforce types but ignore the type of the functions:
typedef enforces type definitions to exist. Rule options:
"call-signature" checks return type of functions
"parameter" checks type specifier of function parameters
"property-declaration" checks return types of interface properties
"variable-declaration" checks variable declarations
"member-variable-declaration" checks member variable declarations
You can use a file like this one to configure TSLint. And read this to learn more about how to configure it.
Edit:
If you're targeting ES5, you can also do something like this:
var bar = (x: string, y: number) : string => {
// do some stuff...
};
class Foo {
get bar () { return bar; }
}
var test = (new Foo).bar('hello', 3);
Or:
class Foo {
get bar () {
return (xx: string, yy: number): string => {
// do some stuff...
};
}
}
This way the method's context is preserved and it also exists on the prototype. There's also no need to copy the argument types, TSC will infer them.

Resources