Typescript KeyOf - Массив или Объект - Отчаянный - PullRequest
0 голосов
/ 31 мая 2018

У меня есть следующий класс .....

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.

Моя проблема в том, что мне нужна функция "AT", которая может обрабатывать объекты keyof и массивы keyof, но кажется, что независимо от того, как я его переделываю, я не могу этого достичь.

для меня это кажется огромным недостатком в машинописи, и массивы, и объекты являются просто объектами, поэтому keyof для типа объекта и keyof для типа массива должны работать одинаково.

1 Ответ

0 голосов
/ 31 мая 2018

Самое простое решение - подождать, пока машинопись 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.
...