Stack Overflow Asked on December 30, 2021
I’m new to TypeScript and struggling to achieve something or even know if it is possible.
I want to be able to define a type for a function which allows instances of the function to set their own return type but at the same time restricts that return type to being an object where the keys are strings and the values are strings.
So the generic type definition should allow any return type matching { [key: string]: string }
but a specific instance of the function could specify that it will return { a: ‘y’, b: ‘z’ } and then when using the returned value of the function the compiler will know that it will only have properties a and b and not just any string properties.
type obj = {
name: string,
doAThing: (path: string) => { [key: string]: string }
}
const anObj: obj = {
name: 'Alias Fakename',
doAThing: path => ({ a: 'abc', b: 'xyz' })
}
const result = anObj.functionInstance('abcdef')
In the above example doAThing
in anObj
is a valid implementation of genericFunction
. But when using result
the compiler does not know that it will only have properties a
and b
and allows any string key to be used e.g. result.keyWhichDoesntExist
does not throw a type error.
Is there a way when defining doAThing
in anObj
to specify its return type so that type hinting will work on result
whilst ensuring that the specified return type conforms to the return type of genericFunction
?
You want to make your function type generic with the <T>
syntax:
type GenericFunction<T extends { [key: string]: string }> = (path: string) => T
This function type accepts another type T
that must have string key names and string values, and whatever that type is, that is what the function returns.
You can then use that type and lock in the type it operates on like so:
const functionInstance: GenericFunction<{ a: string, b: string }> =
(path: string) => ({ a: 'abc', b: 'xyz' })
Now when you use that function, typescript knows the return type is { a: string, b: string }
.
const result = functionInstance('a/path/here')
console.log(result.a) // 'abc'
console.log(result.b) // 'xyz'
You can read more about generics in the handbook.
So this function is part of an interface?
Then you can make the interface itself generic, and do pretty much the same thing:
type MyObj<T extends { [key: string]: string }> = {
name: string,
doAThing: (path: string) => T
}
Now MyObj
accepts the T
generic parameter, and doAThing()
just uses it.
You would create a MyObj
like this:
const anObj: MyObj<{ a: string, b: string }> = {
name: 'Alias Fakename',
// doAThing() return type here is checked to match T
doAThing: path => ({ a: 'abc', b: 'xyz' })
}
And now the return value is strongly typed:
const result = anObj.doAThing('abcdef')
console.log(result.a) // works
console.log(result.b) // works
Answered by Alex Wayne on December 30, 2021
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP