«Крутую ты штуку придумал, Стёпа», — сообщил мне коллега, осознав рассказанную ему идею. Надеюсь это действительно так, хоть и не скажу, что в том, о чём далее пойдёт речь, есть что-то безумно новаторское, однако, на мой взгляд, интерес данный материал всё же представляет.
Сегодня поговорим о применении интроспекции в разработке веб-интерфейсов, немного пошаманим с обобщённым программированием и изобретём велосипед в Typescript, имеющий похожий аналог в .NET.
Википедия гласит, что это возможность запросить тип и структуру объекта во время выполнения программы.
Ну то есть имеется класс:
class Person {
height: number;
weight: number;
bloodPressure: string;
}
Его объект определяется набором полей, каждое из которых имеет, по крайней мере, свой тип и значение.
При этом данный массив мы можем получить в любой момент выполнения программы, вызвав какую-то функцию.
const fields = ObjectFields.of(Person)
Я, конечно, человек с замыленными мозгами, но в данной ситуации буду мыслить шаблонно. Вытянуть имена полей можно с помощью Object.keys
, а типизировать это дело уже через keyof
. Далее используя ключи, как индексы, получаем значения и данные о них.
Пропустив через себя эту информацию, можно выразить свои выводы следующим образом. Начнём с простого, описав некий тип, характеризующий поле объекта.
interface IObjectField<T extends object> {
readonly field: keyof T;
readonly type: string;
readonly value: any;
}
Если задуматься, то можно увидеть, что это сильно напоминает FieldInfo. Правда я это понял в момент написания статьи 🙂
И сейчас самое время вспомнить, что Typescript — это не .NET. Например, создавать экземпляры объекта в контексте обобщённого программирования здесь можно только с помощью фабрик. То есть, как в C# не прокатит.
Если описывать конструктор некого класса, то получится приблизительно следующее.
interface IConstructor<T> {
new(...args: any[]): T;
}
Хорошо, попробуем создать инструмент для интроспекции класса, который бы удовлетворял следующим требованиям:
IObjectField
Вот теперь рассуждения в начале раздела переведены на язык Typescript.
class ObjectFields<T extends object> extends Array<IObjectField<T>> {
readonly [n: number]: IObjectField<T>;
constructor(type: IConstructor<T>) {
const instance: T = new type();
const fields: Array<IObjectField<T>> = (Object.keys(instance) as Array<keyof T>)
.map(x => {
const valueType = typeof instance[x];
let result: IObjectField<T> = {
field: x,
type: valueType === 'object'
? (instance[x] as unknown as object).constructor.name
: valueType,
value: instance[x]
}
return result;
});
super(...fields);
}
}
Попробуем “прочитать” класс Person
и выведем данные на экран.
const fields = new ObjectFields(Person);
console.log(fields);
Правда, вместо ожидаемого вывода получили пустой массив.
Как же так? Всё скомпилировалось и отработало без ошибок. Однако дело в том, что результирующий массив строится с помощью Object.keys
, и поскольку в рантайме работает Javascript, то какой объект засунем, такой набор ключей и получим. А объект — пустой, вот и информация о типах, которую мы попытались извлечь, куда-то потерялась. Чтобы её “вернуть”, необходимо инициализировать поля класса какими-то начальными значениями.
class Person {
height: number = 80;
weight: number = 188;
bloodPressure: string = '120-130 / 80-85';
}
Вуаля — получили, что хотели.
Также протестируем более сложную ситуацию.
class Material {
name = "wood";
}
class MyTableClass {
id = 1;
title = "";
isDeleted = false;
createdAt = new Date();
material = new Material();
}
Результат превзошёл ожидания.
Первое, что пришло в голову: CRUD приложения на react теперь можно писать, реализуя обобщённые компоненты. Например, нужно сделать форму для вставки в таблицу. Пожалуйста, никто не запрещает делать что-то такое.
interface ITypedFormProps<T extends object> {
type: IConstructor<T>;
}
function TypedForm<T extends object>(props: ITypedFormProps<T>) {
return (
<form>
{new ObjectFields(props.type).map(f => mapFieldToInput(f))}
</form>
);
}
И использовать потом этот компонент вот так.
<TypedForm
type={Person} />
Ну и саму таблицу сделать по такому же принципу тоже возможно.
Хочется сказать, что штука получилась интересная, но пока непонятно, что с ней делать дальше. Если вам было интересно или есть какие-либо предложения, пишите в комментариях, а пока до новых встреч! Спасибо за внимание!
Центр управления связью общего пользования (ЦМУ ССОП) Роскомнадзора рекомендовал компаниям из реестра провайдеров ограничить доступ поисковых ботов к информации на российских сайтах.…
Apple возобновила переговоры с OpenAI о возможности внедрения ИИ-технологий в iOS 18, на основе данной операционной системы будут работать новые…
Конкурсный управляющий российской «дочки» Google подготовил 23 иска к участникам рекламного рынка. Общая сумма исков составляет 16 млрд рублей –…
Google завершил обновление основного алгоритма March 2024 Core Update. Раскатка обновлений была завершена 19 апреля, но сообщил об этом поисковик…
У частных продавцов на Авито появилась возможность составлять текст объявлений с помощью нейросети. Новый функционал доступен в категории «Обувь, одежда,…
24 апреля 2024 года в Москве состоялась церемония вручения наград международного конкурса Workspace Digital Awards. В этом году участниками стали…