Welcome toVigges Developer Community-Open, Learning,Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
210 views
in Technique[技术] by (71.8m points)

typescript - What is the way to define an object with a dynamic number of properties?

I'm trying to assign the correct shape to an object that serves as the initialValue of the reduce method. This object can have a dynamic number of properties and the name of the key can be the numbers from 1 to 6, the latter defined in the DiceNumber type

type DiceNumber = 1 | 2 | 3 | 4 | 5 | 6;

const dataset: DiceNumber[] = [];

function rollDice(): DiceNumber {
  return Math.floor(Math.random() * 6 + 1) as DiceNumber;
}

function stats(data: DiceNumber[]) {
  return data.reduce((a, c) => {
    a[c] = (a[c] || 0) + 1;

    return a;
  }, {} as any);
}

dataset.push(rollDice());
dataset.push(rollDice());
dataset.push(rollDice());
dataset.push(rollDice());
dataset.push(rollDice());
dataset.push(rollDice());
dataset.push(rollDice());
dataset.push(rollDice());
dataset.push(rollDice());
dataset.push(rollDice());
dataset.push(rollDice());

console.log(stats(dataset));

By not using any I get the following message

Element implicitly has an 'any' type because expression of type 'DiceNumber' can't be used to index type '{}'. Property '1' does not exist on type '{}'

When trying to define an interface in the following way

interface MyType {
  [key: DiceNumber]: number;
}

I get the following message

An index signature parameter type cannot be a union type. Consider using a mapped object type instead.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

The type you're looking for is indeed a mapped type. I'd suggest:

{ [K in DiceNumber]?: number }

which means for each key K in DiceNumber, the object type has an optional property of type number. You can also use built in utility types and call it Partial<Record<DiceNumber, number>>.

So your function is now:

function stats(data: DiceNumber[]) {
    return data.reduce((a, c) => {
        a[c] = (a[c] || 0) + 1;

        return a;
    }, {} as { [K in DiceNumber]?: number });
}

And you can verify that stats()'s call signature is

/* function stats(data: DiceNumber[]): {
    1?: number | undefined;
    2?: number | undefined;
    3?: number | undefined;
    4?: number | undefined;
    5?: number | undefined;
    6?: number | undefined;
} */

as expected.

Playground link to code


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to Vigges Developer Community for programmer and developer-Open, Learning and Share
...