(при условии, что вы используете TS3.0 или более позднюю версию)
TypeScript поддерживает концепцию строковых литеральных типов , а также типов кортежей , поэтомувозможно получить ваше значение a
для типа ['ONE', 'TWO', 'THREE']
, а также значение ['ONE', 'TWO', 'THREE']
, например:
const a: ['ONE', 'TWO', 'THREE'] = ['ONE', 'TWO', 'THREE'];
(Менее избыточный способ добиться этого случится позже):
Тогда вы можете представить предполагаемый тип b
как отображение ключей на значения, которые точно соответствуют ключу, используя mappedвведите :
type SameValueAsKeys<KS extends string[]> = { [K in KS[number]]: K };
, который можно использовать следующим образом:
const b: SameValueAsKeys<typeof a> = a.reduce((acc, type) => ({ ...acc, [type]: type }), {} as any);
b.ONE; // property type is "ONE"
b.TWO; // property type is "TWO"
b.THREE; // property type is "THREE"
Обратите внимание, как компилятор знает, что b
имеет три ключа, "ONE"
, "TWO"
и "THREE"
, и значения совпадают с ключами.
Таким образом, TypeScript, безусловно, поддерживает этот тип динамической типизации.К сожалению, это немного утомительно, как я показал выше.Одним из способов сделать это менее раздражающим является добавление некоторых вспомогательных функций, которые позволяют компилятору выводить правильные типы или, по крайней мере, скрывать утверждения типов в библиотеке, где разработчику не придется беспокоиться о них.
Во-первых, для a
... компилятор не выводит типы кортежей, а также имеет тенденцию расширять строковые литералы до типа string
, за исключением определенных экземпляров .Давайте введем вспомогательную функцию с именем stringTuple()
:
function stringTuple<T extends string[]>(...args: T) { return args; }
Это выводит тип кортежа из аргументов остальных .Теперь мы можем использовать его для создания a
без ввода избыточных строковых значений:
const a = stringTuple("ONE", "TWO", "THREE");
Далее, давайте представим функцию, которая принимает список строк и возвращает объект, ключи которого являются теми строками и значения которых совпадаютстроки:
function keyArrayToSameValueAsKeys<T extends string[]>(keys: T): SameValueAsKeys<T>;
function keyArrayToSameValueAsKeys(keys: string[]): { [k: string]: string } {
return keys.reduce((acc, type) => ({ ...acc, [type]: type }), {});
}
Здесь мы используем тот же код с reduce
, но мы скрываем его внутри своей собственной функции и используем одну сигнатуру вызова перегрузки для представленияпредполагаемый тип выхода.Теперь мы можем получить b
следующим образом:
const b = keyArrayToSameValueAsKeys(a);
b.ONE; // property type is "ONE"
b.TWO; // property type is "TWO"
b.THREE; // property type is "THREE"
Если вы поместите stringTuple()
и keyArrayToSameValueAsKeys()
в библиотеку, пользователь сможет использовать их без особых проблем:
const otherObject = keyArrayToSameValueAsKeys(stringTuple("x", "y", "z"));
// const otherObject: {X: "X", Y: "Y", Z: "Z"}
Или вы можете объединить их вместе следующим образом:
function keysToSameValueAsKeys<T extends string[]>(...keys: T): { [K in T[number]]: K };
function keysToSameValueAsKeys(keys: string[]): { [k: string]: string } {
return keys.reduce((acc, type) => ({ ...acc, [type]: type }), {});
}
И затем получить результат за один вызов, например так:
const lastOne = keysToSameValueAsKeys("tic", "tac", "toe");
// const lastOne: {tic: "tic", tac: "tac", toe: "toe"};
Хорошо, надеюсь, что этонекоторая помощь.Удачи!