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.
