Типы TypeScript Generic невероятно мощны, они позволяют нам создавать композиции шрифтов, что является удивительным шаблоном, который можно использовать в любом проекте TS.

Как использовать универсальные шаблоны?
Использовать универсальные шаблоны очень просто, нам просто нужно сообщить TS, что наш тип принимает другие типы как «полные».
поэтому, если у нас есть какой-то тип A с некоторым динамическим свойством «dynamicObj» в зависимости от места использования трудно определить все типы свойств статически, потому что нам нужно указать все возможные типы для « dynamicObj ».

type B = {
  keyA: string;
  keyB: string;
}
type C = {
  keyT: number;
  keyV: boolean;
}

Теперь есть простое и совершенно небезопасное решение: «Просто скажите, что dynamicObject имеет тип any»
Конечно, вы никогда не должны использовать это, имея какой-либо тип в вашем код - это огромный признак «запаха кода».
Кроме того, мы можем пойти дальше неизвестного и выполнить приведение типов после.

type A = {
  prop: string;
  dynamicObject: unknown;
};
const aWithB: A = {
  prop: 'ok',
  dynamicObject: {
    keyA: 'test',
    keyB: 'ok'
  }
}
console.log((aWithB.dynamicObject as B).keyA) // NOT SO GOOD 😓 

Мы можем пойти еще дальше, используя UnionType для свойства dynamicObject.

type A = {
  prop: string;
  dynamicObject: B | C;
};
const aWithB: A = {
  prop: 'ok',
  dynamicObject: {
    keyA: 'test',
    keyB: 'ok'
  }
}
console.log(
  (aWithB.dynamicObject as B).keyA // We still need to cast type 😞 
)

Итак, давайте посмотрим, как мы можем решить эту проблему с помощью Generic

Если мы укажем тип A как тип, который имеет некоторые свойства, такие как prop и dynamicObj, мы знаем, что dynamicObj зависит от места использования. Затем мы можем определить тип A как тип, который принимает другой тип, который будет типом свойства dynamicObject. Звучит сложнее, чем есть на самом деле.

type A<DynamicObjectType> = {
  prop: string;
  dynamicObject: DynamicObjectType;
};
const aWithB: A<B> = {
  prop: 'ok',
  dynamicObject: {
    keyA: 'test',
    keyB: 'ok'
  }
}
const aWithC: A<C> = {
  prop: 'ok',
  dynamicObject: {
    keyT: 11,
    keyV: true
  }
}
console.log(aWithB.dynamicObject.keyA);
console.log(aWithC.dynamicObject.keyV);
// No warnings, no compilation error 🤩 

И это значит, что теперь наш тип A масштабируем для расширения до произвольного числа типов, которые могут быть свойством dynamicObject.
Даже это допустимый тип:

const foo: A<number> = {
  prop: "lol",
  dynamicObject: 11
}

Вот как можно использовать всю мощь универсальных шаблонов в шрифтовых композициях, довольно просто!

Удачи!