I have an object that is of type MyObject
, and it has two string properties.
interface MyObject {
a: number,
b: string,
}
const myObject = {
a: 5,
b: 'str'
}
Then I have a function that takes a string, and I want to be able to access the property on the aforementioned object specified by the string parameter. What I am trying to do is use a type guard to check if the string is a key of the object, before I access the property. It is necessary to make some kind of check here because the parameter is just a string and the object doesn't have an index signature.
If I make a specific version to check for this specific type of object (MyObject) it works:
// specific version
const isValidPropertyForMyObject = (property: string): property is keyof MyObject => Object.keys(myObject).indexOf(property) !== -1
const getProperty1 = (property: string) => {
if (isValidPropertyForMyObject(property)) {
myObject[property]
}
}
However, what if I want to be able to pass in an object with a generic type, and a string parameter, and check that the property is in fact a key of the object? Here is my attempt:
const isValidMethodForHandler = <T extends { [i: string]: any }>(handler: T) => (
method: string
): method is keyof T => Object.keys(handler).indexOf(method) !== -1;
const getProperty = (property: string) => {
// const acceptedProperties = ["a", "b"];
// if (acceptedProperties.indexOf(property) !== -1) {
// myObject[property]
// }
if (isValidMethodForHandler(myObject)(property)) {
myObject[property]
}
}
The issue is in the type guard:
A type predicate's type must be assignable to its parameter's type. Type 'keyof T' is not assignable to type 'string'. Type 'string | number | symbol' is not assignable to type 'string'. Type 'number' is not assignable to type 'string'.(2677)
in
operator is much less verbose:if (key in obj) { return obj[key] }
– wrsxgetProperty<T extends { [i: string]: any }>(property: string, obj: T)
– wrsx