I have a type, e.g.:
type Output = {
fieldA?: string;
fieldB?: string;
}
And I have an object, e.g.:
const input = { fieldA: "A", fieldB: "B", other: "C" };
Now I want to map the value to another object of type Output
, so I want to loop through the object keys and assign only when the key is a valid property of type Output
, e.g.:
let output: Output = {};
Object.keys(input).forEach(k => {
if (k is keyof Output) {
output[k] = input[k];
}
});
How do you achieve the above?
CodePudding user response:
TypeScript types are compiled away and not available at runtime, so you can't do this directly. However, you can define the set of valid keys as a type, then use that type to define Output
as an object whose keys are that type.
type Field = 'fieldA' | 'fieldB';
type Output = Partial<Record<Field, string>>;
const input = { fieldA: "A", fieldB: "B", other: "C" };
const fields = new Set<Field>(['fieldA', 'fieldB']);
const output = Object
.keys(input)
.filter((k): k is Field => fields.has(k))
.reduce(
(output, k) => ({ ...output, [k]: input[k] }),
{} as Output
);
Notice the type predicate in filter
: k is Field
. It's saying that when the filter condition is true (i.e. fields.has(k)
), then k
is a Field
. This means that the k
in reduce
will be of type field
instead of string
.
CodePudding user response:
I would honestly advise you to initialize output
with some properties defined in Output
type. So I would approach your scenario this way:
interface Output{
fieldA?: string;
fieldB?: string;
}
let input = {
fieldA : "One",
fieldB : "Two",
fieldC : "Three"
};
let output: Output = {
fieldA: null,
fieldB: null
};
Object.keys(output).forEach((key)=>
{
output[key] = input[key];
});
console.log(output );
This way output
will hold the properties. Imagine a case where input
has not properties that exist in Output
type, they would return undefined. so I would rather create an object that declares those properties even prior to mapping them with the input
.
It's also important to note how the forEach
loop is only interested in the properties existing inside output
of type Output
... the rest won't be mapped.