简体   繁体   中英

How to define filtered array in TypeScript

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?

Just cast to validData[].

const filteredData: validData[] = mixedData.filter((obj: IValid | IError) => !obj.hasOwnProperty('error')) as validData[];

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[]

Playground

Object.prototype.hasOwnProperty.call is much safer than obj.hasOwnProperty , see eslint rule

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM