Skip to main content

prefer-ts-extras-is-property-defined

Require isPropertyDefined from ts-extras in Array.prototype.filter callbacks instead of inline property-undefined checks.

Targeted pattern scopeโ€‹

This rule only inspects inline .filter(...) predicates that perform an explicit undefined check against a single object property.

  • Inline property-undefined predicates inside .filter(...), including:
    • filter((item) => item.prop !== undefined)
    • filter((item) => undefined !== item.prop)
    • filter((item) => item.prop != undefined)
    • filter((item) => typeof item.prop !== "undefined")

Named predicate references, multi-argument callbacks, and broader callback logic are not matched unless they preserve this property-undefined-check shape.

What this rule reportsโ€‹

This rule reports inline filter predicates that check whether a single object property is not undefined and can be normalized with isPropertyDefined.

Why this rule existsโ€‹

filter(isPropertyDefined('prop')) is the canonical ts-extras pattern for filtering out items where a specific property is undefined.

  • Filtering logic is consistent and composable across collections.
  • The property key is explicit in the function call, not hidden inside a callback.
  • Repeated inline !== undefined callback expressions are removed.
  • isPropertyDefined is a proper type predicate that narrows element types in the resulting array.

โŒ Incorrectโ€‹

const named = users.filter((user) => user.name !== undefined);

โœ… Correctโ€‹

import { isPropertyDefined } from "ts-extras";

const named = users.filter(isPropertyDefined("name"));

Behavior and migration notesโ€‹

  • isPropertyDefined('prop') checks item[prop] !== undefined and narrows the result type accordingly.
  • The autofix preserves the property name as a string literal.
  • Deep property access (e.g., user.address.street !== undefined) is intentionally excluded โ€” only single-level property checks are flagged.
  • Computed property access (e.g., user[key] !== undefined) is intentionally excluded.

Additional examplesโ€‹

โŒ Incorrect โ€” typeof formโ€‹

const named = users.filter((user) => typeof user.name !== "undefined");

โœ… Correct โ€” typeof form fixedโ€‹

const named = users.filter(isPropertyDefined("name"));

ESLint flat config exampleโ€‹

import typefest from "eslint-plugin-typefest";

export default [
{
plugins: { typefest },
rules: {
"typefest/prefer-ts-extras-is-property-defined": "error",
},
},
];

When not to use itโ€‹

Disable this rule if your filter callbacks intentionally combine property checks with additional logic, or if the property name is dynamic.

Package documentationโ€‹

ts-extras package documentation:

Source file: source/is-property-defined.ts

/**
Returns a filter predicate that tests whether a given property key is defined (not `undefined`) on an object.

This is useful as a type guard in `Array.prototype.filter` to narrow the resulting array type.

@example
```
import {isPropertyDefined} from 'ts-extras';

interface User {
name: string | undefined;
}

const users: User[] = [{ name: 'Alice' }, { name: undefined }];
const namedUsers = users.filter(isPropertyDefined('name'));
//=> [{ name: 'Alice' }]
```

@category Type guard
*/

Rule catalog ID: R101

Further readingโ€‹