Как исключить только свойства getter из типа в машинописи - PullRequest
0 голосов
/ 21 сентября 2018

Методы получения в классе являются свойствами только для чтения, поэтому имеет смысл выдавать ошибку типа из следующего кода.

class Car {
    engine: number;
    get hp() {
        return this.engine / 2;
    }
    get kw() {
        return this.engine * 2;
    }
}

function applySnapshot(
    car: Car,
    snapshoot: Partial<Car> // <-- how to exclude readonly properties?
) {
    for (const key in snapshoot) {
        if (!snapshoot.hasOwnProperty(key)) continue;
        car[key as keyof Car] = snapshoot[key as keyof Car];
        // Cannot assign to 'hp' because it is a constant or a read-only property.
    }
}

Есть ли способ приведения свойств только для записи для ввода и исключения всех получателей?

пример на игровой площадке

Ответы [ 2 ]

0 голосов
/ 24 сентября 2018

Хотя readonly напрямую не влияет на присваиваемость типов, оно влияет на идентичность.Чтобы проверить, являются ли два типа идентичными, мы можем использовать (1) правило присваиваемости для условных типов, которое требует, чтобы типы после extends были идентичными, или (2) процесс вывода для типов пересечения, который выбрасывает идентичные типыс обеих сторон.Затем мы просто используем сопоставленные типы, как в ответе Тициана Черникова-Драгомира, чтобы посмотреть на каждое свойство Car по очереди и посмотреть, является ли оно идентичным изменяемой версии самого себя.

// https://github.com/Microsoft/TypeScript/issues/27024#issuecomment-421529650
type IfEquals<X, Y, A, B> =
    (<T>() => T extends X ? 1 : 2) extends
    (<T>() => T extends Y ? 1 : 2) ? A : B;

// Alternatively:
/*
type IfEquals<X, Y, A, B> =
    [2] & [0, 1, X] extends [2] & [0, 1, Y] & [0, infer W, unknown]
    ? W extends 1 ? B : A
    : B;
*/

type WritableKeysOf<T> = {
    [P in keyof T]: IfEquals<{ [Q in P]: T[P] }, { -readonly [Q in P]: T[P] }, P, never>
}[keyof T];
type WritablePart<T> = Pick<T, WritableKeysOf<T>>;

class Car {
    engine: number;
    get hp() {
        return this.engine / 2;
    }
    get kw() {
        return this.engine * 2;
    }
}

function applySnapshot(
    car: Car,
    snapshoot: Partial<WritablePart<Car>>
) {
    let key: keyof typeof snapshoot;
    for (key in snapshoot) {
        if (!snapshoot.hasOwnProperty(key)) continue;
        car[key] = snapshoot[key];
    }
}
0 голосов
/ 21 сентября 2018

Редактировать См. @ Matt-mccutchen для интересного решения этой проблемы.

Оригинальный ответ

readonly довольно слабыйМодификатор в этом смысле не влияет на присваиваемость.Например, вы можете назначить объект со свойствами readonly объекту с такими же изменяемыми свойствами, и компилятор не будет жаловаться:

let roCar: Partial<Car> = { hp: 10 } // we can assign a  mutable object to a referecne with a readonly property
roCar.hp = 10; // error hp is readonly

//But we can also assign an object with a readonly property to a fully mutable version of it 
let allMutableCar: { -readonly [P in keyof Car]: Car[P] } = new Car();
allMutableCar.hp = 10; // No compile time error

Это известная проблема, задокументированная здесь ,

Из-за этого правила присваивания в условных типах невозможно различить разницу между полем только для чтения и изменяемым.

Один из способов - добавить что-то дополнительное к типу полей только для чтения.,Это не повлияет на то, как вы можете использовать поле, но даст нам возможность удалить ключ.

type readonly = { readonly?: undefined };
class Car {
    engine!: number;
    get hp() : number & readonly {
        return this.engine / 2;
    }
    get kw() : number & readonly {
        return this.engine * 2;
    }
}

type NoReadonlyKeys<T> = { [P in keyof T]: 'readonly' extends keyof T[P] ? never : P }[keyof T]

type PartialNoReadonly<T> = Partial<Pick<T, NoReadonlyKeys<T>>>  
type Mutable<T> = { -readonly [P in keyof T]: T[P] }
function applySnapshot(
    car: Car,
    snapshoot: PartialNoReadonly<Car>
) {
    const mutableCar: Mutable<Car> = car; // erase readonly so we can mutate
    for (const key in snapshoot) {
        let typedKey = key as keyof typeof snapshoot
        if (!snapshoot.hasOwnProperty(key)) continue;
        mutableCar[typedKey] = snapshoot[typedKey] as any;
    }
}

applySnapshot(new Car(), {
    engine: 0
})
applySnapshot(new Car(), {
    hp: 0 /// error
})
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...