I am trying to do the following in a functional component using TypeScript (I abstracted it a bit):
return <IonToast {canClose && button={close}}
It isn't allowed to wrap a prop inside a conditional. But what would be the best solution to have such logic?
I though about assigning the 'close' variable before the return, but since Ionic is an external component library, it doesn't accept an empty variable.
The IonToast is typed in node-modules with the following. So it doesn't like it if you pass anything but a valid value.
export interface ToastOptions {
buttons?: (ToastButton | string)[];
}
The ts error goes like this
Types of property 'button' are incompatible. Type 'string | boolean | undefined' is not assignable to type 'string | undefined'. Type 'false' is not assignable to type 'string | undefined'.
UPDATED
According to this document
You can have this logic for your buttons attribute
const buttons: ToastButton[] = canClose ? [close] : [] //`close` needs to be `ToastButton` type
return <IonToast buttons={buttons} />
OLD ANSWER
I don't know which is the best solution for this case, but I'm personally using this way
return <IonToast button={canClose ? close : () =>{}} />
The second param is an empty function that would help to prevent errors, just in case you call button() (indirect to close()) in IonToast component.
There are many solution to accomplish this. If you have many properties under the same condition you can wrap them in an object. Since IonToast expect props of a shape -> https://ionicframework.com/docs/api/toast#toastoptions you should use buttons instead of button
return <IonToast {...(canClose && {buttons:[close]})}
Related
I have a demo here
I'm trying to create a simple react hook form with typescript
I have the form displaying locally but for some reason it won't display here abd I get t.split is not a function this is not my question though.
On the inputs I am using ref={register} which is what I have seen in tutorials but on the ref I get the error
Type 'UseFormRegister<User>' is not assignable to type 'LegacyRef<HTMLInputElement>'. Type 'UseFormRegister<User>' is not assignable to type '(instance: HTMLInputElement) => void'. Types of parameters 'name' and 'instance' are incompatible. Type 'HTMLInputElement' is not assignable to type '"email" | "password" | "firstname" | "lastname" | "age" | "confirmpassword"'. Type 'HTMLInputElement' is not assignable to type '"confirmpassword"'.(2322) index.d.ts(137, 9): The expected type comes from property 'ref' which is declared here on type 'DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>'
Does anyone know why this is or how to fix this.
React Refs are of a specific type with a generic type attached (LegacyRef).
The type of register is UseFormRegister<User> which is not compatible with react refs.
Perhaps the tutorial you referenced used register in a different way or another parameter?
I have an array of objects. i am iterating that in loop and passing each item's name to onclick which targets a function navigate(url:string) in cmpenent.ts
html :
{{sousMenu.titre}}
compenent:
navigate(url:string):void{
this.router.navigate( [url]); }
the error message is :
Argument of type 'string | undefined' is not assignable to parameter of type 'string'.
Type 'undefined' is not assignable to type 'string'.ngtsc(2345)
Can you provide a complete code example so we can advise on the total context.
Sometimes if a property is defined with a type of 'string | undefined' additional handling is needed when the function calls for only a 'string'.
Some of the things you can do are the following:
navigate(url:string | undefined):void{
this.router.navigate( [url as string]);
}
That might not be the best route but without further viewing of the code it's hard to see how we may expand on it.
I'm trying to understand why can't I use Pick utility type to pick one property from my interface and use it to type my component's state.
Here's the interface:
export interface IBooking {
...
propertyId: string | null;
...
}
And then in my component I have the following:
const [propertyId, setPropertyId] = useState<Pick<IBooking, 'propertyId'>>('some-id');
This is the error I get:
TS2345: Argument of type 'string' is not assignable to parameter of type 'Pick | (() => Pick )'.
However, if I just replace Pick<IBooking, 'propertyId'> with string | null, it, of course, works. And I don't understand what is the difference. Isn't it exactly what Pick type should do? I didn't have much experience with utility types, but I'm using Pick type perfectly fine in another place. Is it because some specifics of useState hook?
What am I missing here?
Thanks in advance.
Assuming that propertyId on IBooking is of the type string | null then it will be the following type:
{
propertyId: string | null;
}
The result of Pick is an object containing only attributes which are listed.
You can use a lookup type like this instead:
IBooking["propertyId"]
I am trying to implement rtl support in a project using material-ui, as described here. my problem is in stage 4.1. I am trying to create a new cache instance that uses the stylis-plugin-rtl. the example povided in the documentation is in javascript & I'm trying to port that into typescript. I have two problems. first, I am trying to pass stylis plugins to the createCache function but I get this error:
Type '(element: Element, index: number, children: Element[], callback: Middleware) => string | void' is not assignable to type 'Plugin'.
Types of parameters 'element' and 'context' are incompatible.
Type 'import("/home/ehsun/Desktop/volkswagen/packages/swiss-army-knife/node_modules/#emotion/stylis/types/index").Context' is not assignable to type 'Element'.ts(2322)
which I bypassed like this:
const cacheRtl = createCache({
key: 'muirtl',
stylisPlugins: [
(prefixer as unknown) as StylisPlugin,
(rtlPlugin as unknown) as StylisPlugin,
],
});
the second problem is that the CacheProvider component has a problem with the type of the created cache & gives this warning:
Property 'insert' is missing in type 'import("/node_modules/#emotion/utils/types/index").EmotionCache' but required in type 'import("/node_modules/#emotion/react/node_modules/#emotion/utils/types/index").EmotionCache'.ts(2741)
index.d.ts(26, 3): 'insert' is declared here.
index.d.ts(338, 9): The expected type comes from property 'value' which is declared here on type 'IntrinsicAttributes & ProviderProps<EmotionCache>'
which I bypassed by casting the cache as any
<CacheProvider value={cacheRtl as any}>{children}</CacheProvider>
I feel like both solutions are wrong/incompelete, and a result of me being a bit inexperienced with typescript, so I would love to know if you people had a better idea. thanks in advance.
I have a form component "AddBooking" that takes the following prop:
type AddBookingProps = { edit?: Booking };
If this "edit" prop is passed in, I want to render the form with the values set. If it isn't passed in, it becomes a "create" blank form. This is how I'm trying to use the state.
const [currentBooking, setBooking] = useState<NewBooking | Booking>(
edit ? edit : emptyBooking
);
emptyBooking is just a load of empty strings in a NewBooking type to initialize the state.
The difference between the types "Booking" and "NewBooking" is that "Booking" has a required "_id" type whereas "NewBooking" doesn't.
The methods I have for editBooking and addBooking required types "Booking" and "NewBooking" respectively. This is where I get type errors:
if (edit) {
bookingContext.editBooking(currentBooking);
handleClose();
} else {
bookingContext.addBooking({
...currentBooking,
bookedBy: uContext.user.username
});
handleClose();
}
I get a type error when calling editBooking:
Argument of type 'NewBooking | Booking' is not assignable to parameter of type 'Booking'.
Property '_id' is missing in type 'NewBooking' but required in type 'Booking'.
Any ideas how I can get around this without the "any" type?
Thanks so much
This maybe a use case for a type guard https://www.typescriptlang.org/docs/handbook/advanced-types.html#type-guards-and-differentiating-types
A function you define to check that _id is actually on the type. This is probably good practice as you don't want the user to edit a booking that doesn't yet exist