I have an array i want to filter with typescript, however i can't get the typescript validation side working, i have an array of actions, and i want to filter out the internal actions (see below) - however i cannot tell typescript that the filteredActions array no longer contains internalAction!
Here's what i tried:
type ActionName = 'replaceText' | 'replaceImage' | 'internalAction';
interface Action {
name: ActionName
}
const INTERNAL_ACTIONS = ['internalAction'] as const;
type InternalActions = typeof INTERNAL_ACTIONS[number];
const actions: Action[] = [{
name: 'replaceText'
}, {
name: 'replaceImage'
}, {
name: 'internalAction'
}];
const isInternalAction = (name: ActionName): name is Exclude<ActionName, InternalActions> => name in INTERNAL_SLIDE_ACTIONS;
const filteredActions = actions.filter((action) => !isInternalAction(action.name));
for (const action of filteredActions) {
if (action.name === 'internalAction') {
// i'd expect TS to throw an error here as internalAction should never appear
}
if (action.name === 'replaceImage') {
// i'd expect TS to NOT throw an error here
}
}
CodePudding user response:
the issue is in isInternalAction
arrow function.
in order to check if an element in an array in typescript you cannot use in operator, but you can use: includes, some, find, indexOf (maybe there is other options but these are on the top of my head)
so I would change your code to for example:
type ActionName = 'replaceText' | 'replaceImage' | 'internalAction';
interface Action {
name: ActionName
}
const INTERNAL_ACTIONS: readonly ActionName[] = ['internalAction'] as const;
type InternalActions = typeof INTERNAL_ACTIONS[number];
const actions: Action[] = [{
name: 'replaceText'
}, {
name: 'replaceImage'
}, {
name: 'internalAction'
}];
// use includes to check if element exists in an array
const isInternalAction = (name: ActionName): boolean => INTERNAL_ACTIONS.includes(name);
const filteredActions = actions.filter((action) => !isInternalAction(action.name));
console.log(filteredActions)
here you can find and run the snippet above in a ts-playground
CodePudding user response:
The trick was the filter, I had to rebind the action with the names excluded:
const filteredActions = slide.actions.filter((action): action is Omit<Action, 'name'> & {
name: Exclude<ActionName, InternalActions>
} => typeof INTERNAL_ACTIONS.find(i => i === action.name) === 'undefined');
This way each action after filtering has the correct typings