prefer-ts-extras-key-in
Prefer keyIn from ts-extras over key in object checks.
keyIn(...) provides better key narrowing for dynamic property checks.
Targeted pattern scopeโ
This rule focuses on direct key in object expressions that can be migrated to keyIn(key, object) with deterministic fixes.
- Native
key in objectexpressions that can usekeyIn(key, object).
Alias indirection, wrapper helpers, and non-canonical call shapes are excluded to keep keyIn(key, object) migrations safe.
What this rule reportsโ
This rule reports key in object expressions when keyIn(key, object) is the intended replacement.
- Native
key in objectexpressions that can usekeyIn(key, object).
Why this rule existsโ
keyIn expresses key-membership checks with a helper that improves key narrowing in typed code.
- Dynamic key checks have one canonical form.
- Guarded property access needs fewer casts.
- Membership guards are easier to audit in review.
โ Incorrectโ
if (key in payload) {
// ...
}
โ Correctโ
if (keyIn(key, payload)) {
// ...
}
Behavior and migration notesโ
- Runtime semantics match the
inoperator for property existence on object/prototype chains. keyInis useful when key values start asstring/PropertyKeyand need narrowing.- If your code intentionally requires direct
insyntax (for style or tooling), keep native checks.
Additional examplesโ
โ Incorrect โ Additional exampleโ
if (candidate in record) {
console.log(record[candidate as keyof typeof record]);
}
โ Correct โ Additional exampleโ
if (keyIn(candidate, record)) {
console.log(record[candidate]);
}
โ Correct โ Repository-wide usageโ
const canRead = keyIn(data, selectedKey);
ESLint flat config exampleโ
import typefest from "eslint-plugin-typefest";
export default [
{
plugins: { typefest },
rules: {
"typefest/prefer-ts-extras-key-in": "error",
},
},
];
When not to use itโ
Disable this rule if direct in expressions are required by coding standards.
Package documentationโ
ts-extras package documentation:
Source file: source/key-in.ts
/**
Check if a key exists in an object and narrow the key type.
This function performs __key narrowing__ - it narrows the key variable to only keys that actually exist in the object. Uses the `in` operator to check the entire prototype chain.
When `keyIn` returns `true`, the key is narrowed to keys that exist in the object.
When it returns `false`, the key type remains unchanged.
Unlike `objectHasIn` and `objectHasOwn` (both do object narrowing), this narrows the _key_ type, making it useful for validating union types of possible keys.
@example
```
import {keyIn} from 'ts-extras';
const object = {foo: 1, bar: 2};
const key = 'foo' as 'foo' | 'bar' | 'baz';
if (keyIn(object, key)) {
// `key` is now: 'foo' | 'bar' (narrowed from union)
console.log(object[key]); // Safe access
} else {
// `key` remains: 'foo' | 'bar' | 'baz' (unchanged)
}
// Works with symbols
const symbol = Symbol.for('myKey');
const objectWithSymbol = {[symbol]: 'value'};
if (keyIn(objectWithSymbol, symbol)) {
// symbol is narrowed to existing symbol keys
}
```
@note This uses the `in` operator and checks the prototype chain, but blocks `__proto__` and `constructor` for security.
@category Type guard
*/
Rule catalog ID: R024