I want to find a way how to pass different objects to one same function and let the function process only inputs that are present in the given object. Specifically I am passing different Angular Components as this and am destructuring the object attributes.

export function filterVisualData({data, playersOn, typesOn, resultsOn, toBeRemoved, teamsOn, xGOn, shotsOn}) {
  return data.filter(d => {
    const result = d.success ? 'Successful' : 'Unsuccessful';
    const players = playersOn.length === 0 || (playersOn.length > 0 && playersOn.includes(d.player_name));
    const types = typesOn.length === 0 || (typesOn.length > 0 && typesOn.includes(capitalizeAllWords(d.type)));
    const results = resultsOn.length === 0 || (resultsOn.length > 0 && resultsOn.includes(result));
    const removed = !toBeRemoved.map(p => p.time).includes(d.time);
    const shots = shotsOn.length === 0 || (shotsOn.length > 0 && shotsOn.includes(d.type));
    const xG = xGOn.length === 0 || (xGOn.length > 0 && d.xG < Math.max(...xGOn));
    const teams = teamsOn.length === 0 || (teamsOn.length > 0 && teamsOn.includes(d.team_name));
    return players && types && results && removed && shots && xG && teams;
  });
}

The problem is that some components are missing some attributes and I get this error

TS2345: Argument of type 'this' is not assignable to parameter of type '{ data: any; playersOn: any; typesOn: any; resultsOn: any; toBeRemoved: any; teamsOn: any; xGOn: any; shotsOn: any; }'.   Type 'ShotChart' is not assignable to type '{ data: any; playersOn: any; typesOn: any; resultsOn: any; toBeRemoved: any; teamsOn: any; xGOn: any; shotsOn: any; }'.     Property 'typesOn' is missing in type 'ShotChart'.

2

There are 2 answers

1
Jeremy Thille On BEST ANSWER

You can pass any object without Typescript complaining, by doing something like this :

export function filterVisualData(obj: any) {

    const { data, playersOn, typesOn, resultsOn, toBeRemoved, teamsOn, xGOn, shotsOn } = obj

    return data.filter(d => {
        const result = d.success ? 'Successful' : 'Unsuccessful';
        const players = playersOn.length === 0 || (playersOn.length > 0 && playersOn.includes(d.player_name));
        const types = typesOn.length === 0 || (typesOn.length > 0 && typesOn.includes(capitalizeAllWords(d.type)));
        const results = resultsOn.length === 0 || (resultsOn.length > 0 && resultsOn.includes(result));
        const removed = !toBeRemoved.map(p => p.time).includes(d.time);
        const shots = shotsOn.length === 0 || (shotsOn.length > 0 && shotsOn.includes(d.type));
        const xG = xGOn.length === 0 || (xGOn.length > 0 && d.xG < Math.max(...xGOn));
        const teams = teamsOn.length === 0 || (teamsOn.length > 0 && teamsOn.includes(d.team_name));
        return players && types && results && removed && shots && xG && teams;
    });
}

So you get no error at compile time, but you will still get errors at runtime. If you don't pass playersOn, then you'll get a Cannot read length of undefined crash. You need to implement failsafes for each value.

0
smtaha512 On

You can also leverage interfaces and Partial built into TypeScript.

export interface IData {
    success: boolean;
    player_name: string;
    type: string;
    time: string;
    team_name: string;
}
export interface IBaseArgs {
    data: IData[] , 
    playersOn: <TypeHere>, 
    typesOn: <TypeHere>, 
    resultsOn: <TypeHere>, 
    toBeRemoved: <TypeHere>, 
    teamsOn: <TypeHere>, 
    xGOn: <TypeHere>, 
    shotsOn: <TypeHere>
}

export function filterVisualData<T extends Partial<IBaseArgs>>(obj: T) {
  const {data, playersOn, typesOn, resultsOn, toBeRemoved, teamsOn, xGOn, shotsOn} = obj;
  return data.filter(d => {
    const result = d.success ? 'Successful' : 'Unsuccessful';
    const players = playersOn.length === 0 || (playersOn.length > 0 && playersOn.includes(d.player_name));
    const types = typesOn.length === 0 || (typesOn.length > 0 && typesOn.includes(capitalizeAllWords(d.type)));
    const results = resultsOn.length === 0 || (resultsOn.length > 0 && resultsOn.includes(result));
    const removed = !toBeRemoved.map(p => p.time).includes(d.time);
    const shots = shotsOn.length === 0 || (shotsOn.length > 0 && shotsOn.includes(d.type));
    const xG = xGOn.length === 0 || (xGOn.length > 0 && d.xG < Math.max(...xGOn));
    const teams = teamsOn.length === 0 || (teamsOn.length > 0 && teamsOn.includes(d.team_name));
    return players && types && results && removed && shots && xG && teams;
  });
}

Using Partial will make all the keys optional and the function will accept the objects that have some missing keys. You will also get IntelliSense.