Issue
How do I make sure that the specified keyof a type extends an array?
For example I have this type:
type TestType = {
arrayKey: Array<number>,
notArrayKey: number
}
And I have this function that will access the specified key of the type:
const getKey = <T>(object: T, key: keyof T): Array<any> => {
return object[key]
}
How do I make sure that the only valid input of key are arrayKey as it extends Array and not "notArrayKey" which does not extends Array?
Solution
Behemoth's answer will provide good IntelliSense suggestions for the key if you choose to use the parameter order of (object, key).
More simply, if you reverse the parameters, you can use generic constraints to ensure that the object argument conforms to a type having an array value at the key argument provided:
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) */
Expanding on the other answer:
The type mapping can be performed in the generic constraint in order to provide a type parameter name to use in the return type.
In the example below, when the obj value is provided as the first argument to the function, the generic type Obj becomes the type of that object, and the type parameter Key becomes a union of all of its properties which have value types that extend readonly any[] (which means an immutable array with elements of any type). This union ends up looking like 'arrayKey' | 'anotherArrayKey', so the value provided to key has to be one of those strings, or a compiler error diagnostic will be emitted.
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 type
>(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) */
Answered By - jsejcksn
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.