UNPKG

ts-extras

Version:

Essential utilities for TypeScript projects

42 lines (32 loc) 1.78 kB
import type { IsLiteral, UnknownRecord } from 'type-fest'; type HasWidenedKey<Key extends PropertyKey> = string extends Key ? true : number extends Key ? true : symbol extends Key ? true : false; type NarrowedKey<ObjectType, Key extends PropertyKey> = HasWidenedKey<Key> extends true ? Key : IsLiteral<Key> extends true ? Extract<Key, Exclude<keyof ObjectType, '__proto__' | 'constructor'>> : Key; /** 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 */ export declare function keyIn<ObjectType extends UnknownRecord, Key extends PropertyKey>(object: ObjectType, key: Key): key is NarrowedKey<ObjectType, Key> & {}; export {};