Reputation: 1365
I have an array with two possible values. It might include an expected object, or an object which defines an error. The data could look something like this:
// mixedData
[
{ item1: "value", item2: "value2" },
{ error: true, description: "no value found" },
];
I made two types for this array. One for a valid object and one for the error object. I then defined my array like this:
const myArray: Array<IValid | IError> = [] // fetched from api
Next I want to remove every object with an error field from the array, leaving me with IValid
objects only:
const filteredData: IValid[] = mixedData.filter(
(obj: IValid | IError) => !obj.hasOwnProperty("error")
);
This works but TypeScript does not really like this because it still thinks an item could be of IError
:
Error: Type '(IValid| IError)[]' is not assignable to type 'IValid[]'.
How do I make TypeScript happy here?
Upvotes: 1
Views: 241
Reputation: 1714
Simple example with Type Guards
interface IValid { item1: string; item2: string };
interface IError { error: boolean; description: string };
const data: Array<IValid | IError> = [
{ item1: "value", item2: "value2" },
{ error: true, description: "no value found" },
];
function isValid(obj: IValid | IError): obj is IValid {
return (obj as IError).error === undefined;
}
const filteredValidData = data.filter(isValid);
console.log(filteredValidData);
// [ { item1: "value", item2: "value2" } ]
Other examples from documentation
Upvotes: 1
Reputation: 33041
You can just use typeguard as a filter
predicate:
type IValid = { item1: string, item2: string }
type IError = { error: boolean, description: string }
type All = IValid | IError
const data: All[] = [
{ item1: 'value', item2: 'value2' },
{ error: true, description: 'no value found' }
]
const myArray: Array<IValid | IError> = [] // fetched from api
const hasProperty = <Obj, Prop extends string>(obj: Obj, prop: Prop)
: obj is Obj & Record<Prop, unknown> =>
Object.prototype.hasOwnProperty.call(obj, prop);
const filteredData = data.filter((obj): obj is IValid /** here is the trick */ => !hasProperty(obj, 'error')); // IValid[]
Object.prototype.hasOwnProperty.call
is much safer than obj.hasOwnProperty
, see eslint rule
Upvotes: 1
Reputation: 21
Just cast to validData[].
const filteredData: validData[] = mixedData.filter((obj: IValid | IError) => !obj.hasOwnProperty('error')) as validData[];
Upvotes: 2