Create your own 'objectKeys' function using generics and the 'keyof' operator
A common pain point when using TypeScript is when you have this Object.keys
function here. My object here has keys a b and c but when I try to iterate over its keys when I've extracted them from Object.keys
, the key is typed as a string.
That means that when I try to access it I get this horrible long type error. No index signature with parameter of type string was found in type
a b c.
export const myObject = { a: 1, b: 2, c: 3,}Object.keys(myObject).forEach((key) => { console.log(myObject[key])})
So this really should be typed as keyof myObject
and the way to get around this is to create your own Object.keys
function.
So we'll create our function objectKeys
which has a generic Obj
. We'll set that as the type for our argument obj
and then set the return type to be an array of keyof Obj
.
const objectKeys = <Obj>(obj: Obj): (keyof Obj)[] => {}
Then we'll return Object.keys(obj) as (keyof Obj)[]
. We are using the as
to make a type assertion. This tells the compiler to infer the result of Object.keys(obj)
to be an array of the objects keys as strings.
const objectKeys = <Obj>(obj: Obj): (keyof Obj)[] => { return Object.keys(obj) as (keyof Obj)[]}
So now if we go objectKeys(myObject)
then key is typed as a b or c.
objectKeys(myObject).forEach((key) => { console.log(myObject[key])})
Transcript
0:00 A common pain point when using TypeScript is when you have this object.keys function here. MyObject here has keys A, B, and C, but when I try to iterate over its keys when I've extracted them from object.keys, then the key is typed as a string. That means that when I try to access it, I get this horrible long type error, "No index signature with parameter of type 'string' was found in type A, B, C."
0:23 This should be typed as key of myObject. The way to get around this is to create your own object.keys function, so object.keys=. We're going to have Obj, which is our object. We're going to add that to the generics list here. Then we're going to return a keyof Obj, and that is going to be in an array like this.
0:47 Here, "A function whose declared type is neither 'void'...and must return a value." We just need to return Object.keys(obj) as...Yeah, we can do this instead. Now, if we go object.keys(myObject), then key is typed as A, B, or C.
The looseness of Object.keys
can be a real pain point when using TypeScript. Luckily, it's pretty simple to create a tighter version using generics and the keyof
operator.
More Tips
Type Predicates
1 min
TypeScript 5.1 Beta is OUT!
2 mins
How to Name your Types
4 mins
Don't use return types, unless...
4 mins
TypeScript 5.0 Beta Deep Dive
6 mins
Conform a Derived Type Without Losing Its Literal Values
1 min
Avoid unexpected behavior of React’s useState
1 min
Understand assignability in TypeScript
2 mins
Compare function overloads and generics
1 min
Use infer in combination with string literals to manipulate keys of objects
1 min
Access deeper parts of objects and arrays
1 min
Ensure that all call sites must be given value
1 min
Understand how TypeScript infers literal types
1 min
Get a TypeScript package ready for release to NPM in under 2 minutes
1 min
Use assertion functions inside classes
1 min
Assign local variables to default generic slots to dry up your code and improve performance
2 mins
Know when to use generics
2 mins
Map over a union type
1 min
Make accessing objects safer by enabling 'noUncheckedIndexedAccess' in tsconfig
1 min
Use generics to dynamically specify the number, and type, of arguments to functions
1 min
Use 'declare global' to allow types to cross module boundaries
2 mins
Turn a module into a type
2 mins
Create autocomplete helper which allows for arbitrary values
2 mins
Use deep partials to help with mocking an entity
1 min
Throw detailed error messages for type checks
1 min
Create a 'key remover' function which can process any generic object
1 min
Use generics in React to make dynamic and flexible components
1 min
Write your own 'PropsFrom' helper to extract props from any React component
1 min
Use 'extends' keyword to narrow the value of a generic
1 min
Use function overloads and generics to type a compose function
2 mins
Decode URL search params at the type level with ts-toolbelt
2 mins
Use 'in' operator to transform a union to another union
2 mins
Derive a union type from an object
2 mins