Behemoth's response contains helpful IntelliSense suggestions for the key if you decide to follow the parameter order of (object, key)
.
To put it simply, by switching the parameters, you can utilize generic constraints to verify that the object
argument adheres to a type with an array value at the specified key
:
TS Playground
function getValueInObj <
Key extends string,
Obj extends Record<Key, readonly any[]>,
>(key: Key, object: Obj): Obj[Key] {
return object[key];
}
const obj = {
arrayKey: [1, 2, 3],
nonArrayKey: '123',
};
getValueInObj('arrayKey', obj); // OK
getValueInObj('nonArrayKey', obj); /*
~~~
Argument of type '{ arrayKey: number[]; nonArrayKey: string; }' is not assignable to parameter of type 'Record<"nonArrayKey", readonly any[]>'.
Types of property 'nonArrayKey' are incompatible.
Type 'string' is not assignable to type 'readonly any[]'.(2345) */
Building upon the previous response:
The type mapping can be achieved in the generic constraint to assign a type parameter name for use in the return type.
In the code snippet below, when the obj
value is passed as the first argument to the function, the generic type Obj
transforms into the type of that object, while the type parameter Key
becomes a union of all its properties with value types extending readonly any[]
(indicating an immutable array with elements of any type). This union is represented as 'arrayKey' | 'anotherArrayKey'
, requiring the value provided to key
to be one of those strings, otherwise a compiler error will be triggered.
TS Playground
function getValueInObj <
Obj extends Record<PropertyKey, any>,
Key extends keyof {
[
K in keyof Obj as Obj[K] extends readonly any[]
? K
: never
]: unknown; // The "unknown" type used here as the value doesn't matter
}, // because it goes unused: it could be any
>(object: Obj, key: Key): Obj[Key] {
return object[key];
}
const obj = {
arrayKey: [1, 2, 3],
anotherArrayKey: ['a', 'b', 'c'],
nonArrayKey: '123',
};
getValueInObj(obj, 'arrayKey'); // number[]
getValueInObj(obj, 'nonArrayKey'); /*
~~~~~~~~~~~~~
Argument of type '"nonArrayKey"' is not assignable to parameter of type '"arrayKey" | "anotherArrayKey"'.(2345) */