Я бы предложил сделать функцию generi c как типа groupLabelKey
, так и типа groupValuesKey
, например:
class CountryFilterFormatterService {
public groupCountriesByRegion<LK extends string, VK extends string>(
groupLabelKey: LK,
groupValuesKey: VK,
): { [K in LK | VK]: string }[] {
return [
{
[groupLabelKey]: 'foo',
[groupValuesKey]: 'bar'
} as { [K in LK | VK]: string }
]
}
}
Там это два универсальных параметра типа c: LK
и VK
, соответствующие (надеюсь) строковым литералам типов значений, переданных для groupLabelKey
и groupValuesKey
соответственно. Тип возвращаемого значения - это массив сопоставленного типа , {[K in LK | VK]: string}
. Это означает «объект, ключи которого LK
и VK
, а значения которого в этих ключах string
s».
Здесь есть морщина в том, что значение { [groupLabelKey]: 'foo', [groupValuesKey]: 'bar' }
не распознается компилятор как имеющий правильный тип. Он видит обобщенный c вычисленный ключ и расширяет его до string
, и, следовательно, тип этого объекта определяется как { [k: string]: string }
, и компилятор будет жаловаться, если вы вернете его как есть. Существует открытая проблема GitHub по этому поводу, microsoft / TypeScript # 13948 , но пока что так оно и есть.
Обходной путь - использовать утверждение типа в качестве Я сделал выше, и добавляю as { [K in LK | VK]: string }
после литерала объекта. Есть и другие обходные пути, но этот не касается кода времени выполнения.
Итак, давайте посмотрим, работает ли он:
const x = (new CountryFilterFormatterService()).groupCountriesByRegion("baz", "qux");
// const x: { baz: string; qux: string; }[]
x.forEach(
v => console.log(v.baz.toUpperCase() + " " + v.qux.toUpperCase())
); // FOO BAR
Хорошо выглядит. Я передал "baz"
и "qux"
, и компилятор видит тип x
как Array<{baz: string, qux: string}>
, как вы, вероятно, хотите.
Хорошо, надеюсь, это поможет; удачи!
Детская площадка ссылка на код