A reusable predicate function can narrow values inside array methods.

predicate A function that returns a boolean can capture the guard logic used by `filter`.

Predicate Function

secondActive
predicate.ts
Replay: real traced execution (multi-file project)
type User = {
    name: string;
    active: boolean;
};

function isActive(user: User): boolean {
    return user.active;
}

const secondActive: boolean = false;
const users: User[] = [
    { name: "Ada", active: true },
    { name: "Milo", active: secondActive },
    { name: "Lin", active: false },
];

const activeNames: string = users.filter(isActive).map((user) => user.name).join(",");

console.log(activeNames);
type User = {
    name: string;
    active: boolean;
};

function isActive(user: User): boolean {
    return user.active;
}

const secondActive: boolean = true;
const users: User[] = [
    { name: "Ada", active: true },
    { name: "Milo", active: secondActive },
    { name: "Lin", active: false },
];

const activeNames: string = users.filter(isActive).map((user) => user.name).join(",");

console.log(activeNames);
  1. secondActive ← false, users ← [object Object],[object Object],[object Object]

    7    return user.active;8}910const secondActive→ false: boolean = false;  //@secondActive=true11const users→ [object Object],[object Object],[object Object]: User[] = [12    { name: "Ada", active: true },13    { name: "Milo", active: secondActivefalse },14    { name: "Lin", active: false },15];1617const activeNames: string = users[object Object],[object Object],[object Object].filter(isActivefunction isActive(user) {
        console.log("@@TRACE|predicate.ts|-1|ENTER|4.3-6.41-8.2:\n\nfunction isActive(user: User): boolean {|" + ("6.19-6.23:user:" + String(user).length + ":" + String(user)) + "@@END");
        console.log("@@TRACE|predicate.ts|-1|BEFORE|6.41-7.24:\n    return user.active;|" + ("7.11-7.23: user.active:" + String(user.active).length + ":" + String(user.active)) + "@@END");
        console.log("@@TRACE|predicate.ts|-1|LEAVE|4.3-6.41-8.2:\n\nfunction isActive(user: User): boolean {|@@END");
        return user.active;
    }).map((user) => user.name).join(",");
  2. function isActive(user: User): boolean

    pass 1 of 3
    3    active: boolean;4};56function isActive(user[object Object]: User): boolean {7    return user.activetrue;8}
    All 3 passes — pass 1 is the card above
    passuser.active
    1true
    2false
    3false
  3. activeNames ← Ada

    14    { name: "Lin", active: false },15];1617const activeNames→ Ada: string = users[object Object],[object Object],[object Object].filter(isActivefunction isActive(user) {
        console.log("@@TRACE|predicate.ts|-1|ENTER|4.3-6.41-8.2:\n\nfunction isActive(user: User): boolean {|" + ("6.19-6.23:user:" + String(user).length + ":" + String(user)) + "@@END");
        console.log("@@TRACE|predicate.ts|-1|BEFORE|6.41-7.24:\n    return user.active;|" + ("7.11-7.23: user.active:" + String(user.active).length + ":" + String(user.active)) + "@@END");
        console.log("@@TRACE|predicate.ts|-1|LEAVE|4.3-6.41-8.2:\n\nfunction isActive(user: User): boolean {|@@END");
        return user.active;
    }).map((user) => user.name).join(",");1819console.log(activeNamesAda);
    outputAda
  1. secondActive ← true, users ← [object Object],[object Object],[object Object]

    7    return user.active;8}910const secondActive→ true: boolean = true;11const users→ [object Object],[object Object],[object Object]: User[] = [12    { name: "Ada", active: true },13    { name: "Milo", active: secondActivetrue },14    { name: "Lin", active: false },15];1617const activeNames: string = users[object Object],[object Object],[object Object].filter(isActivefunction isActive(user) {
        console.log("@@TRACE|predicate.ts|-1|ENTER|4.3-6.41-8.2:\n\nfunction isActive(user: User): boolean {|" + ("6.19-6.23:user:" + String(user).length + ":" + String(user)) + "@@END");
        console.log("@@TRACE|predicate.ts|-1|BEFORE|6.41-7.24:\n    return user.active;|" + ("7.11-7.23: user.active:" + String(user.active).length + ":" + String(user.active)) + "@@END");
        console.log("@@TRACE|predicate.ts|-1|LEAVE|4.3-6.41-8.2:\n\nfunction isActive(user: User): boolean {|@@END");
        return user.active;
    }).map((user) => user.name).join(",");
  2. function isActive(user: User): boolean

    pass 1 of 3
    3    active: boolean;4};56function isActive(user[object Object]: User): boolean {7    return user.activetrue;8}
    All 3 passes — pass 1 is the card above
    passuser.active
    1true
    2true
    3false
  3. activeNames ← Ada,Milo

    14    { name: "Lin", active: false },15];1617const activeNames→ Ada,Milo: string = users[object Object],[object Object],[object Object].filter(isActivefunction isActive(user) {
        console.log("@@TRACE|predicate.ts|-1|ENTER|4.3-6.41-8.2:\n\nfunction isActive(user: User): boolean {|" + ("6.19-6.23:user:" + String(user).length + ":" + String(user)) + "@@END");
        console.log("@@TRACE|predicate.ts|-1|BEFORE|6.41-7.24:\n    return user.active;|" + ("7.11-7.23: user.active:" + String(user.active).length + ":" + String(user.active)) + "@@END");
        console.log("@@TRACE|predicate.ts|-1|LEAVE|4.3-6.41-8.2:\n\nfunction isActive(user: User): boolean {|@@END");
        return user.active;
    }).map((user) => user.name).join(",");1819console.log(activeNamesAda,Milo);
    outputAda,Milo