#typescript
Вопрос:
У меня есть следующий код машинописи:
const formatters = {
time(value: string): string {
const serialized = moment(value, dateTimeFormat, true);
return serialized.format('MMM Do YYYY HH:mm');
},
date(value: string): string {
const serialized = moment(value, 'YYYY-MM-DD', true);
return serialized.format('MMM Do YYYY');
},
stringUpperCase(value: string): string {
return value.toUpperCase();
},
// ...
}
Затем я хочу попробовать динамически найти форматер таким образом:
function getFormattedValue(type: string): string {
const formatter = formatters[type] || formatters.stringUpperCase;
// ...
}
Однако я получаю эту ошибку машинописи:
Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ time(value: string): string; date(value: string): string; stringUpperCase(value: string): string; ... }'.
No index signature with a parameter of type 'string' was found on type '{ time(value: string): string; date(value: string): string; stringUpperCase(value: string): string;... }'.ts(7053)
(property) type: string
Как мне решить эту проблему?
Ответ №1:
formatters
не может быть проиндексирован, string
потому что в качестве имен свойств существуют только три определенные строки.
Поэтому вам нужно сообщить typescript, что вы ожидаете type
, что это будет одно из имен свойств formatters
. Ты делаешь это с keyof
помощью . Любая другая строка должна быть ошибкой типа.
function getFormattedValue(
type: keyof typeof formatters,
value: string
): string {
const formatter = formatters[type];
return formatter(value)
}
Который вы бы использовали вот так:
// Works
getFormattedValue('time', 'a timestamp here')
getFormattedValue('date', 'a date here')
getFormattedValue('stringUpperCase', 'a string here')
// Error as expected
getFormattedValue('asdasd', 'a type error here')
// Argument of type '"asdasd"' is not assignable to parameter of type
// '"time" | "date" | "stringUpperCase"'.(2345)
Комментарии:
1. Я
Argument of type 'string' is not assignable to parameter of type 'never'.ts(2345)
к чему-то клонюformatter(value)
. Есть какие-нибудь идеи?2. Код, который я опубликовал, не отображает эту ошибку, так что вы, должно быть, делаете что-то другое. Если вы отредактируете свой вопрос с кодом, который показывает эту ошибку, я, вероятно, смогу сказать вам, что не так.
3. О!
formatter(value)
может принимать различные типы (число, строка, логическое значение, объекты различной структуры и т.д.). Как это тогда исправить?4. Это значительно усложняет ситуацию. У меня может не хватить времени написать это, но это работает: tsplay.dev/wXkxDW
Ответ №2:
Во-первых, время(значение: строка) не является строкой, поэтому вы не можете получить доступ к своей функции, введя формат[«время»]. Это должно быть {time: (value: string): string => { //your function }
Во-вторых, вам нужно объявить форматеры, поскольку {[type: string]: Function}
typescript знает, что строка может использоваться для индексирования «форматеров», и он знает, что тип результирующего значения будет функцией.
В целом, ваш код будет выглядеть так:
const formatters: {[type: string]: Function} = {
time: (value: string): string => {
const serialized = moment(value, dateTimeFormat, true);
return serialized.format('MMM Do YYYY HH:mm');
},
date: (value: string): string => {
const serialized = moment(value, 'YYYY-MM-DD', true);
return serialized.format('MMM Do YYYY');
},
stringUpperCase: (value: string): string => {
return value.toUpperCase();
},
// ...
}
function getFormattedValue(type: string): string {
const formatter = formatters[type] || formatters.stringUpperCase;
// ...
}