繁体   English   中英

打字稿:推断嵌套keyof属性的类型

[英]Typescript: Infer type of nested keyof Properties

我想定义一个Array类型,它必须包含给定类型的嵌套属性名称链。

假设我有一个类型:

    type Foo = {
        outer: {
            inner: any;
        }
    }

现在我想定义一个包含2个元素的Array类型:

type PropertyList<T, K1 extends keyof T, K2 extends keyof T[K1]> = [K1, K2];

我想这样使用它:

let myList:PropertyList<Foo> = ["outer", "inner"]

所以我希望编译器检查2包含的属性名是否是Foo的嵌套属性名。

但我不能只用一个通用参数定义PropertyList,然后我得到这个错误:

TS2314: Generic type 'PropertyList' requires 3 type argument(s)

知道我怎么能推断出嵌套的keyof类型而不必指定它们?

关于如何做到这一点的第一个近似值是在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

您可以使用函数来帮助根据传递的实际参数推断核心类型。 我们需要使用双函数方法,因为我们需要为TK1K2设置泛型参数,但我们只想指定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
}

编辑

我想我误解了你的问题,不认为这是可能的(还)。 也许可以通过类型推断来推断位置类型,条件类型将包含在即将发布的TypeScript版本2.8中。

我将在下面留下原始答案以防万一。


类型参数可以具有默认值:

type PropertyList<T, K1 extends keyof T = keyof T, K2 extends keyof T[K1] = keyof T[K1]> = [K1, K2];

但也许在你的情况下,不指定K1K2作为类型参数更有意义:

type PropertyList<T> = [keyof T, keyof T[keyof T]];

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM