I struggled to find a satisfactory way to define arrays with conditional elements, despite the various methods discussed here. As a result, I decided to simplify the declaration process by creating a helper function. While the helper function itself is straightforward in vanilla JavaScript, I encountered challenges when trying to incorporate generics.
JavaScript version
const nin = Symbol('nin')
const includeIf = (condition, item) =>
(typeof condition === "function" ? condition(item) : condition) ? item : nin
const conditionalArray = (init) =>
init(includeIf).filter(item => item !== nin)
/* USAGE */
const cond = false
// should equal ['foo', 'bar', 'qux'] and have type string[]
const arr1 = conditionalArray(addIf => [
'foo',
'bar',
addIf(cond, 'baz'),
addIf(word => word.length < 10, 'qux')
])
// should equal [{ name: 'Alice', age: 23 }] and have type { name: string, age: number }[]
const arr2 = conditionalArray(addIf => [
{ name: 'Alice', age: 23 },
addIf(false, { name: 'Bob', age: 34 }),
addIf(person => person.age > 18, { name: 'Charlie', age: 5 })
])
Updated TypeScript Version with assistance from jcalz
type Narrowable = string | number | boolean | undefined | null | void | {};
const nin = Symbol('nin')
type AddIf = <T, U>(condition: ((x: T) => boolean) | boolean, itemIfTrue: T, itemIfFalse?: U | typeof nin) => T | U | typeof nin
const addIf: AddIf = (condition, itemIfTrue, itemIfFalse = nin) => {
return (typeof condition === "function" ? condition(itemIfTrue) : condition) ? itemIfTrue : itemIfFalse
}
const conditionalArray = <T extends Narrowable>(init: (addIf: AddIf) => Array<T | typeof nin>) =>
init(addIf).filter((item): item is T => item !== nin)