Как начинающий пользователь машинописного текста, у меня возникли проблемы даже с формулировкой вопроса, поэтому, пожалуйста, подождите. (как тип), а затем иметь функцию, которая обеспечивает выполнение интерфейса valueObject на основе переданного ключа.
Я считаю, что лучше всего это объяснить на примере:
// This is an pseudo example stub, not actually working
type ReplaceableWith<T> = string;
// ^ the type I'd like to enforce as the argument
const templates = {
// templateId // template // define somehow the interface required for this template
'animal.sound': 'A {animal} goes {sound}' as ReplaceableWith<{ animal: string; sound: string}>
};
function renderTemplate(
templateId , // must be a key of templates
params // must match value object type, based on templateId
): string {
let rendered = templates[templateId];
for (const [key, value] of Object.entries(params)) {
// replace keys from template with values
rendered = rendered.replace('{' + key + '}', value);
}
return rendered;
}
const a = renderTemplate('animal.sound', { animal: 'Dog', sound: 'woof' })
// ^ a = 'A Dog goes woof'
const b = renderTemplate('animal.sound', { name: 'Some' });
// ^ should throw TS error
Очевидно, это пример не работает, но я думаю, что он демонстрирует то, что я пытаюсь достичь. Я безуспешно предпринял несколько необразованных попыток с keyof, generics и enums.
Возможно ли такое сопоставление типов (или поиск)?
Обновление (рабочий пример)
После некоторой игры, вот рабочий пример с потенциальным решением:
type TemplateKeys = {
'animal.sound': { animal: string; sound: string };
'animal.sleep': { location: string };
'animal.herd': { expectedCount: number; available: number };
'animal.think': undefined;
};
const templates: {[key in keyof TemplateKeys]: string} = {
'animal.sound': '{animal} goes {sound}',
'animal.sleep': 'It sleeps in {location}',
'animal.herd': 'There is {available} animals out of {expectedCount}',
'animal.think': 'Its thinking'
};
function renderTemplate<K extends keyof TemplateKeys>(key: K, params?: TemplateKeys[K]): string {
if (params !== undefined) {
//@ts-ignore
return Object.entries(params).reduce((previousValue: string, [param, value]: [string, any]) => {
return previousValue.replace('{' + param + '}', value);
}, templates[key]);
}
return templates[key];
}
console.log(renderTemplate('animal.sound', { animal: 'Dog', sound: 'woof' }));
console.log(renderTemplate('animal.sleep', { location: 'a hut' }));
console.log(renderTemplate('animal.herd', { expectedCount: 20, available: 10 }));
console.log(renderTemplate('animal.think'));
Выводы:
[LOG]: Dog goes woof
[LOG]: It sleeps in a hut
[LOG]: There is 10 animals out of 20
[LOG]: Its thinking
Хотя это работает, у него есть две проблемы:
- Мне нужно дважды определить ключи (в интерфейсе и экземпляре).
- Интерфейс параметров и сообщение разделены, в идеале они должны быть вместе.