I'm coming from JS background and learning Typescript now. I can't get over this issue. I have a very particularly typed state that I know I will need in the future to work with:
type NotificationValuesType = {
channel: string
for: NotificationUsageTypes
id: string
type: NotificationTypes
workspace: string
}[]
I'm setting my React state like this:
const [dropdownsState, setDropdownsState] = useState<NotificationValuesType>([])
The thing is that initially I can now only type
and id
, all of the rest of props I can gather thru a series of dropdowns when a user chooses them, event fires, and then populates the state with one dropdown at a time, so at some point, it will be only:
[{id: "id", type: "type", channel: "channel"}]
at the next event, it will be [{id: "id", type: "type", channel: "channel", workspace: "workspace"}]
and one more step and state update to get to know all the props in the declared type.
What I don't understand is how to tell Typescript to stop yelling at me until the point I know all the props and make sure I will know all the needed props in the future.
- I absolutely cannot make any of these props optional because they
aren't optional. - Also tried setting state type to
NotificationValuesType | []
but typescript keeps yelling - I learned about type assertions and guess it should help but can't find any example of using it on the state. Can I do something
like
const [dropdownsState, setDropdownsState] = useState as <NotificationValuesType>([])
???
Thanks for reading all way to the end! =)
CodePudding user response:
I absolutely cannot make any of these props optional because they aren't optional.
Perhaps not when you're done, but while you're in the process of building it, if values need to be undefined
, then the type needs to reflect that. So most likely you'll want to have the state variable have optional properties, then you go through your steps to fill it out, and once you've verified it's all there you can assign it to a variable with a type where the properties are all mandatory.
There is a helper type called Partial
which will take in a type and produce a new one who's properties are optional.
// Note: this type is just the individual object, not the array that you have
type Example = {
channel: string
for: NotificationUsageTypes
id: string
type: NotificationTypes
workspace: string
}
const [dropdownsState, setDropdownsState] = useState<Partial<Example>[]>([])
// Later on, once you've verified that all the properties exist you can
// assert that it's done. I don't know exactly what your verification
// code will look like, but here's an example
if (dropdownsState.every(value => {
return value.channel && value.for && value.id && value.type && value.workspace
})) {
const finishedState = dropdownsState as Example[];
// do something with the finished state
}
EDIT: as pointed out in the comments, if you use a type guard, then typescript can narrow down the types and save you from having to reassign it:
if (dropdownsState.every((value): value is Example => {
return value.channel && value.for && value.id && value.type && value.workspace
})) {
// Inside this block, typescript knows that dropdownsState is an Example[]
}