Typescript KeyOf - 数组或对象 - 绝望

时间:2018-05-31 03:01:18

标签: typescript typescript-typings typescript-types

我有以下课程......

export class Person<T, C = T> {
    lens: any = null;
    private value: T;

    constructor(value: T, newLens?: any) {
        this.value = value;
        this.lens = newLens;
    }

    at<K extends keyof C>(path: keyof C): Person<T, C[K]> {
        if(!this.lens) {
            return new Person<T, C[K]>(this.value, Lens.lens(path));
        }
        return new Person<T, C[K]>(this.value, Lens.compose(this.lens)(Lens.lens(path)));
    }

    get(): any {
        if(!this.lens) return this.value;
        return Lens.get(this.lens)(this.value);
    }

    set(f: (newValue: any) => any): T {
        return Lens.set(this.lens)(f(this.get()))(this.value);
    }
}

我的问题是,当我尝试在对象上使用我的新Person类时,我得到了错误的行为.....

const TestPerson = {
      name: {
          name: "steve"
      },
      siblings: [{name: "shanon"}]
      age: Infinity
}

const test = new Person(TestPerson).at("name").at("name") // works....
const test2 = new Person(TestPerson).at("siblings").at(0) // fails
const test3 = new Person(TestPerson).at(siblings").at("0") // still fails.
const test4 = new Person(TestPerson).at("nonexistantproperty") //correctly fails.

我的问题是我需要一个可以处理keyof对象和keyof数组的“AT”函数,但似乎无论我如何重做它都无法实现这一点。

对我来说,这似乎是一个带有打字稿的巨大缺陷,数组和对象都只是引擎盖下的对象,因此对象类型的keyof和数组类型的keyof应该以相同的方式工作。

1 个答案:

答案 0 :(得分:1)

最简单的解决方案是等到打字稿2.9(在写RC时)应尽快发布。在2.9 keyof之前只返回字符串索引,在2.9中,这将包括数字和符号键。请参阅PR。在2.9中,您的代码将按预期工作而不做任何更改。

在2.8中,您可以使用条件类型来实现类似的效果

type CReturn<C, K extends keyof C> = C extends Array<any> ? C[number] : C[K];
export class Person<T, C = T> {
    lens: any = null;
    private value: T;

    constructor(value: T, newLens?: any) {
        this.value = value;
        this.lens = newLens;
    }

    at<K extends keyof C>(path: C extends Array<any> ? number : K): Person<T, CReturn<C, K>> {
        if(!this.lens) {
            return new Person<T, CReturn<C, K>>(this.value, Lens.lens(path));
        }
        return new Person<T, CReturn<C, K>>(this.value, Lens.compose(this.lens)(Lens.lens(path)));
    }
}
const TestPerson = {
    name: {
        name: "steve"
    },
    siblings: [{ name: "shanon" }],
    age: Infinity
}

const test = new Person(TestPerson).at("name").at("name") // works....
const test2 = new Person(TestPerson).at("siblings").at(0) // ok
const test21 = new Person(TestPerson).at("siblings").at(0).at("name") //ok
const test4 = new Person(TestPerson).at("nonexistantproperty") //correctly fails.