I have a function like this:
function flatten(tree, property) {
// ... implementation
return tree[property];s
}
I would like to restrict types of arguments with TypeScript so that it would be generic and fit the type like this:
type Tree = {
subTree: Tree;
name: string;
}
e.g.
function flatten(tree: Tree, property: 'subTree'): Tree {
// ... implementation
return tree[property];
}
But with generics:
function flatten<T, K>(tree: T, property: K): T {
return tree[property];
}
The above of course doesn't work
I looked at this Typescript: object with at least one property of type T but it's not what I want
I would like to restrict type T
so it has at least one property named K
of type T
CodePudding user response:
You can write recursive constraints, so you should make sure that property
is of a generic type K
constrained to a keylike type (the PropertyKey
utility type is just an alias for string | number | symbol
), and that tree
is of a generic type T
constrained to Record<K, T>
(the Record<K, T>
utility type is just an alias for a simple mapped type saying a type with properties of type T
at the keys of type K
):
function flatten<T extends Record<K, T>, K extends PropertyKey>(tree: T, property: K): T {
return tree[property];
}
That compiles with no error. Let's test it on your example structure:
type Tree = {
subTree: Tree;
name: string;
}
declare const tree: Tree;
flatten(tree, "subTree"); // okay
flatten(tree, "name"); // error
Looks good. If you pass in "name"
as the property
, then tree
is not a valid structure (since tree.name
is not of the same type as tree
), but if you pass in "subTree"
then everything is fine.