Mapped types can rename keys while building a related object shape.

Remapped Event Keys

remapped_events.ts
type Model = {
    width: number;
    height: number;
};

type ChangeEvents<T> = {
    [K in keyof T as `${string & K}Changed`]: T[K];
};

function summarizeEvent(events: ChangeEvents<Model>, key: keyof ChangeEvents<Model>): string {
    return `${key}:${events[key]}`;
}

const eventKey: keyof ChangeEvents<Model> = ;
const events: ChangeEvents<Model> = {
    widthChanged: 10,
    heightChanged: 6,
};

console.log(summarizeEvent(events, eventKey));
type Model = {
    width: number;
    height: number;
};

type ChangeEvents<T> = {
    [K in keyof T as `${string & K}Changed`]: T[K];
};

function summarizeEvent(events: ChangeEvents<Model>, key: keyof ChangeEvents<Model>): string {
    return `${key}:${events[key]}`;
}

const eventKey: keyof ChangeEvents<Model> = ;
const events: ChangeEvents<Model> = {
    widthChanged: 10,
    heightChanged: 6,
};

console.log(summarizeEvent(events, eventKey));
key remapping The `as` clause in a mapped type can produce new property names from old keys.