我想定义一个Array类型,它必须包含给定类型的嵌套属性名称链。
我们说我有一个类型:
const userList :User[]=[
{
name :'Swito snowi' ,
avatar_url :'http://magicpackint.com/wp-content/uploads/2015/09/man.jpg'
}]
现在我想定义一个包含2个元素的数组类型:
type Foo = {
outer: {
inner: any;
}
}
我想这样用:
type PropertyList<T, K1 extends keyof T, K2 extends keyof T[K1]> = [K1, K2];
所以我希望编译器检查2包含的属性名是否是Foo的嵌套属性名。
但我只能用一个通用参数定义PropertyList,然后我得到这个错误:
let myList:PropertyList<Foo> = ["outer", "inner"]
我知道如何推断嵌套的keyof类型而不必指定它们吗?
答案 0 :(得分:3)
如何做到这一点的第一个近似值是在Tao的答案中,问题是如果添加更多属性,它将无法按预期工作:
type Foo = {
outer: {
inner: any;
}
outer2: {
inner2: any;
}
}
type PropertyList<T, K1 extends keyof T = keyof T, K2 extends keyof T[K1] = keyof T[K1]> = [K1, K2];
let myList:PropertyList<Foo> = ["outer", "inner"] // error, since K2 will have to be a property of both outer and outer2
您可以使用函数来帮助根据传递的实际参数推断核心类型。我们需要使用双函数方法,因为我们需要为T
,K1
和K2
设置通用参数,但我们只想指定T
,如果我们指定一个我们必须指定所有参数:
function pathFor<T>() {
return function <K1 extends keyof T, K2 extends keyof T[K1]>(outer: K1, inner: K2): [K1,K2]{
return [outer, inner];
}
}
// Usage
let myList = pathFor<Foo>()("outer", "inner"); // typed as ["outer, "inner"]
let myList2 = pathFor<Foo>()("outer2", "inner"); // error, inner is not part of outer2
let myList3 = pathFor<Foo>()("outer2", "inner2"); // typed as ["outer2, "inner2"]
修改
您还可以展开函数以将路径设置为有限长度(示例中为4,但根据需要添加更多):
function keysFor<T>() {
function keys<K1 extends keyof T, K2 extends keyof T[K1], K3 extends keyof T[K1][K2], K4 extends keyof T[K1][K2][K3]>(outer: K1, inner: K2, innerInner: K3, innerInnerInner: K4): [K1,K2, K3, K4]
function keys<K1 extends keyof T, K2 extends keyof T[K1], K3 extends keyof T[K1][K2]>(outer: K1, inner: K2, innerInner: K3): [K1,K2, K3]
function keys<K1 extends keyof T, K2 extends keyof T[K1]>(outer: K1, inner: K2): [K1,K2]
function keys(): string[]{
return [...arguments];
}
return keys
}