No argument, no type argument


const [undefinedThing, setUndefinedThing] = useState()


The problem with this code is that when you don't set the type argument and you don't pass anything in, the thing you create will be undefined. What this means is that you won't ever to be able to set undefinedThing to anything at all.

No argument, type argument


const [stringThing, setStringThing] = useState<string>()


The type for this will actually be set as either string or undefined since the argument is undefined. This does have some valid use-cases.

Argument, no type argument


const [emptyArray, setEmptyArray] = useState([])


When you pass an argument, but don't set a type argument, you might run into the problem of the type being set incorrectly. It does work, and if you pass something like a string it will behave as expected.

But, if you pass an empty array as the initial state, it's going to set the type to be an array of never. So you won't ever be able to add anything to your array.

Argument, type argument


const [arrayOfIds, setArrayOfIds] = useState<{ id: string }[]>([])


And here I have a proper instance of useState with an initial argument and a type argument set.

You will want to do this when you are passing empty objects and arrays as the initial state.