Scenario
You are using a function called doFunkyStuff
from a library called funky-lib
. Do doFunkyStuff
returns an interface FunkyStuff
, but funky-lib
does not export FunkyStuff
The lib code
// node_modules/funcky-lib/index.ts
interface FunkyStuff {
message: string,
funkinessLevel: number
}
export function doFunkyStuff(): FunkyStuff {
console.log('doing funky stuff')
return {
message: 'did some funky stuff',
funkinessLevel: Math.random(),
}
}
Our Code
// index.ts
import { doFunkyStuff } from 'funky-stuff'
// eslint yells no-explicit-any
function repeatFunkyStuff(fStuff: any) {
console.log('repeating funky stuff', fStuff)
return {...fStuff}
}
repeatFunkyStuff(doFunkyStuff)
Depending on your eslint-config, eslint would either yell "no-implicit-any" or "no-explicit-any"
Bad Solution
Redefine FunkyStuff
function repeatFunkyStuff(fStuff: { message: string; funkinessLevel: number})
The solution above is bad because it becomes unreadable if FunkyStuff
has more than a handful of properties.
Also, we must update our code each time something changes in FunkyStuff
.
Good solution
Use the ReturnType
utility type.
// our code in index.ts
...
type AppFunkyStuff = ReturnType<typeof doFunkyStuff>
function repeatFunkyStuff(fStuff: AppFunkyStuff) {
...
}
...
Bonus
You can combine ReturnType<T>
with Awaited<T>
util type for functions that return promises.
Assuming doFunkyStuff
returns Promise, then AppFunkyStuff
would be defined like this.
type AppFunkyStuff = Awaited<ReturnType<typeof doFunkyStuff>>
⚠️ Awaited util became only available in typescript 4.5. Achieving the same effect can be a little tricky. Previous versions
Summary
This tip is just the tip of the iceberg regarding what typescript offers.
Top comments (0)