TS. Как правильно типизировать DTO в методе register(), чтобы пропала ошибка в блоке if-else?

Рейтинг: 0Ответов: 1Опубликовано: 17.03.2023

Имеется следующий код:

class CustomerDTO {
    public sameProp1!: string;
    public sameProp2!: string;
    public sameProp3!: string;
    public role!: string;
    public diffrentProp111!: string;
}

class TrainerDTO {
    public sameProp1!: string;
    public sameProp2!: string;
    public sameProp3!: string;
    public role!: string;
    public diffrentProp222!: string;
}

class AuthSevice {
    constructor() {}

    async register(dto: CustomerDTO | TrainerDTO) {
        const {sameProp1, sameProp2, sameProp3, role} = dto;

        const user = {
            sameProp1,
            sameProp2,
            sameProp3,
            role,
            registrationDate: new Date().toISOString(),
        };

        let customer;
        let trainer;

        if (role === 'customer') {
            customer = {
                ...user,
                diffrentProp111: dto?.diffrentProp111
            }
        } else {
            trainer = {
                ...user,
                diffrentProp222: dto?.diffrentProp222
            }
        }
    }
}

Метод register может получать данные двух видов. И в зависимости от того какие данные были получены мне нужно собрать, или объект customer, или объект trainer. Вот только сделать это не получается потому-то тайпскрипт ругается. И я не могу понять что не так, почему опциональная цепочка(?.) не срабатывает в коде dto?.diffrentProp111 и dto?.diffrentProp222.

Ответы

▲ 1

В вашем случаи надо использовать Type Guards. Если у вас CustomerDTO и TrainerDTO являются классами, то можно сделать проверку if (dto instanceof CustomerDTO).

Также можно явно проверить наличие нужного вам свойства в объекте или использовать ключевые слова typeof или in. Для особо сложных ситуаций (или чтобы четко в коде указать что происходит проверка типов) можно написать функцию типа

function isFoo(arg: any): arg is Foo {...}

Вот рабочий пример для вашего кода:

class CustomerDTO {
    public sameProp1!: string;
    public sameProp2!: string;
    public sameProp3!: string;
    public role!: string;
    public diffrentProp111!: string;
}

class TrainerDTO {
    public sameProp1!: string;
    public sameProp2!: string;
    public sameProp3!: string;
    public role!: string;
    public diffrentProp222!: string;
}

class AuthSevice {
    constructor() {}

    async register(dto: CustomerDTO | TrainerDTO) {
        const {sameProp1, sameProp2, sameProp3, role} = dto;

        const user = {
            sameProp1,
            sameProp2,
            sameProp3,
            role,
            registrationDate: new Date().toISOString(),
        };

        let customer;
        let trainer;

        if (dto instanceof CustomerDTO) {
            customer = {
                ...user,
                diffrentProp111: dto.diffrentProp111
            }
        } else {
            trainer = {
                ...user,
                diffrentProp222: dto.diffrentProp222
            }
        }
    }
}