Reputation: 64
I'm trying to assign string type to "player" with TypeScript in React but it's not working simply with player: string
as in Option 1.
Option 1:
Object.values(data.val()).forEach((player: string) => {
newPlayers.push(player);
});
The above way produces a ts err:
Argument of type '(player: string) => null' is not assignable to parameter of type '(value: unknown, index: number, array: unknown[]) => null'. Types of parameters 'player' and 'value' are incompatible. Type 'unknown' is not assignable to type 'string'.ts(2345)
but using the as-syntax, like the following, corrects it. Why is that?
Option 2:
DB_players.once('value', (data) => {
// Fetch players who signed up
const newPlayers: string[] = [];
if (data.val() ) {
Object.values(data.val()).forEach((player) => {
newPlayers.push(player as string);
});
setPlayers(newPlayers); // save the new player list
}
});
Upvotes: 0
Views: 1182
Reputation: 42258
The type of player
in your map function is not something that you should need to assign. The type comes from the element type of the array which you are mapping.
Typescript thinks that the values of the object returned by data.val()
are of type unknown
. This is the error that you need to fix. Preferably, you should fix it higher up in the code where the data
object is created by saying that data.val()
returns a Record<string, string>
or other type with string values. As a bandaid, you can tell typescript that you are using it as an array of strings by writing (Object.values(data.val()) as string[])
and your error will go away.
Unrelated to the typescript error, @kind user is right that you should not use map
if you aren't returning anything. If newPlayers
is an existing array that already has data in it which you are adding to then you can keep your push
, but do it in a forEach
loop instead. If this is where you are creating the newPlayers
array and it has one entry for every player in data.val
then you could create it from the return value of a map
-- except that you aren't actually doing any mapping here, you're just returning the same value.
This one-liner does the same thing as your loop, which is append all the names in data.val()
to an existing array. The ...
means that they will be added as individual entries.
newPlayers.push( ...Object.values(data.val()) as string[] );
If you post more of the code -- where data
comes from and where newPlayers
is initialized then I can give you a better solution.
Edit:
For creating the array, you can just use the object values directly.
const newPlayers = Object.values(data.val()) as string[];
or
setPlayers( Object.values(data.val() ) as string[] );
Upvotes: 2
Reputation: 625
The problem is Object.values(data.val()) don't return an array of strings.
When you skip the type of player in your arrow function it is implicitely considered as any, which is compatible with the type you try to iterate over.
const newPlayers: string[] = [];
let toto = {a: "test", b: "hello"};
Object.values(toto).map((player: string) => {
newPlayers.push(player);
});
Upvotes: 0