Type Guards and Narrowing
Predicate Function
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
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);
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(",");function isActive(user: User): boolean
pass 1 of 33 active: boolean;4};56function isActive(user[object Object]: User): boolean {7 return user.activetrue;8}All 3 passes — pass 1 is the card above pass user.active1 true 2 false 3 false 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
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(",");function isActive(user: User): boolean
pass 1 of 33 active: boolean;4};56function isActive(user[object Object]: User): boolean {7 return user.activetrue;8}All 3 passes — pass 1 is the card above pass user.active1 true 2 true 3 false 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