@romaro

Как правильно написать дженерик вместо наследования?

Я хочу создать дженерик-тип, который будет добавлять общие свойства к переданному в него интерфейсу. Например, у всех объектов, которые соответствуют типу ActionResult должно быть свойство httpStatus с типом HttpStatus:

type HttpStatus = 200 | 404 | 500;

interface SendJsonActionDto {
    json: JsonObject;
}

type ActionResult<T> = {
    [K in keyof T]: T[K];
    httpStatus: HttpStatus;
}

export class BaseAction {
    public static sendJson(obj: JsonObject): ActionResult<SendJsonActionDto> {
        return {
            json: obj,
            httpStatus: 200
        }
    }
}


Я получаю ошибку при попытке явно добавить свойство с именем httpStatus в интерфейс ActionResult. Пока не нашел этого в документации, но подозреваю, что запись вида [K in keyof T] отменяет все более узкие декларации, т.к. TS не знает заранее, что будет передано в T.

Понятно, что можно решить через наследование (и наверное это даже более правильный подход):
interface Common {
    httpStatus: HttpStatus;
}

interface SendJsonActionDto extends Common {
    json: JsonObject;
}


Но хотелось бы лучше понимать дженерики.
  • Вопрос задан
  • 40 просмотров
Решения вопроса 1
vabka
@vabka
Токсичный шарпист
Попробуй так:
type HttpStatus = 200 | 404 | 500;
type JsonObject = any;
interface SendJsonActionDto {
    json: JsonObject;
}

interface ActionResult {
  httpStatus: HttpStatus
}

type RichActionResult<T> = {
  [Property in keyof T as Exclude<Property, "httpStatus">]: T[Property];
} & ActionResult; 
// Чтобы обойти ошибку "A mapped type may not declare properties or methods" и показать, что httpStatus будет наш, а не тот, который был изначально в T

class BaseAction {
    public static sendJson(obj: JsonObject): RichActionResult<SendJsonActionDto> {
        return {
            json: obj,
            httpStatus: 200
        }
    }
}
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы