问题
I have a data structure that represents the results from a database query, which is an object with many properties, all scalars (in my case, all either strings or numbers). I want to extract a portion of these properties and fill out a new object that has a defined shape.
const input: Record<string, string | number> = { name: 'Jane', age: 42, fav_pet: 'Dog', fav_col: 'Blue', fav_dest: 'Paris' };
const FAVS = ['pet', 'col', 'dest'] as const;
type FavsType = {
pet: string;
col: string;
dest: string;
}
const output: FavsType = FAVS.reduce((acc, key) => ({ ...acc, [key]: input['fav' + key] }), {});
// ~~~~~~
// ^^^^^^ Type '{}' is missing the following properties from type 'FavsType': pet, col, dest
The problem is, if I use the reduce
method to do this, Typescript is unable to figure out that the return value of the reduce must contain an object in the correct shape. I've also tried using Object.fromEntries(FAVS.map())
with similar results.
Is there any type-safe solution to this which doesn't involve assigning each property explicitly?
Playground Link
回答1:
Be Typescript. When Typescript encounter the reduce, it have to declare new variables that it have to type.
const output: FavsType = FAVS.reduce((acc, key) => ({
...acc,
[key]: input[`fav${key}`],
}), ------> {} <------);
The accumulator being initialized as {}
then typescript infer the type '{}'
.
Mutating the accumulator won't change it's type from typescript point of view.
You will have to tell typescript
Trust me, the returned type is of FavsType
That's where assertions comes in :
const output: FavsType = FAVS.reduce((acc, key) => ({
...acc,
[key]: input[`fav${key}`],
}), {}) as FavsType;
Ideally typescript should see the mutation of the object and infer the proper reduce returned type, but it ain't that "smart" yet.
来源:https://stackoverflow.com/questions/62551919/is-there-a-type-safe-way-to-reduce-a-larger-object-into-a-new-type-in-typescri