Как динамически приводить значение машинописи - PullRequest
0 голосов
/ 27 апреля 2020

У меня есть хранилище, которое имеет два метода: create и edit. Create метод получает первый аргумент типа A, а edit получает первый аргумент типа B. У меня есть следующий сценарий:

interface A {
    foo: string;
}

interface B {
    bar: string;
}

class AddressRepository {
    public create(obj: A) {
        // do stuff
    }

    public edit(obj: B) {
        // do stuff
    }
}

let operation: 'create' | 'edit' = true ? 'create' : 'edit';
let obj: A | B = {
    foo: 'bar'
};

(new AddressRepository())[operation](obj);

Я получаю следующую ошибку: Argument of type 'A' is not assignable to parameter of type 'A & B'. Property 'bar' is missing in type 'A' but required in type 'B'.. Как я могу сказать компилятору, что тип переменной obj будет определяться на основе значения переменной operation?

детская площадка

1 Ответ

0 голосов
/ 27 апреля 2020

Концептуально, вы должны link два параметра (имя операции и объект). Для этого вы можете использовать несколько интерфейсов, каждый из которых определяет полный объект с именем операции и входным значением. Это можно использовать в качестве типа «объединение», где клавиша operation будет действовать как дискриминатор, сообщая механизму TS, какое значение вы используете для операции:

type AInput = {
    operation: 'create',
    obj: A;
}

type BInput = {
    operation: 'edit',
    obj: B;
}

const action: AInput | BInput = { operation: 'edit', obj: { bar: 'abc' } };

(new AddressRepository())[action.operation](action.obj);

Это не будет ошибка выброса ( см. на детской площадке ), поскольку TS теперь знает, что action.obj строго связано с action.operation.

Более того, вы можете автоматически извлекать (если хотите) эти введите непосредственно из класса, например:

type AddressRepositoryInput = {
    [K in keyof AddressRepository]: AddressRepository[K] extends (obj: infer TObj) => infer R
    ? { type: K, obj: TObj }
    : never;
}[keyof AddressRepository];

, затем вы можете просто набрать:

const action: AddressRepositoryInput = { type: 'edit', obj: { ... } };

, и он подтвердит ваш ввод.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...