Как определить свойства в интерфейсе Typescript с динамическими элементами в имени ключа?

У меня есть объект, который может иметь n количество свойств, каждое из которых одинаково, но с их n значением в имени.

Пример:

const obj = {
  'data-element-0': 'something',
  'data-element-1': 'something else',
  'data-element-2': 'something as well',
  'data-element-3': 'something to feel included',
};

Есть ли способ определить этот интерфейс более конкретно, чем просто использовать

interface Obj {
  [key: string]: string;
}

Каковы ваши ограничения? Должны ли индексы начинаться с 0? Должны ли они быть целыми числами? Должны ли они быть последовательными целыми числами без пробелов? и т.д.

jcalz 15.12.2020 15:27

Если они должны быть последовательными без пробелов, существует ли разумный максимум n или он потенциально неограничен?

jcalz 15.12.2020 15:56

Почему вы не используете string[]?

Norbert Bartko 15.12.2020 17:07
Зод: сила проверки и преобразования данных
Зод: сила проверки и преобразования данных
Сегодня я хочу познакомить вас с библиотекой Zod и раскрыть некоторые ее особенности, например, возможности валидации и трансформации данных, а также...
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Мне нравится библиотека Mantine Component , но заставить ее работать без проблем с Remix бывает непросто.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
TypeScript против JavaScript
TypeScript против JavaScript
TypeScript vs JavaScript - в чем различия и какой из них выбрать?
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Не все нужно хранить на стороне сервера. Иногда все, что вам нужно, это постоянное хранилище на стороне клиента для хранения уникальных для клиента...
Что такое ленивая загрузка в Angular и как ее применять
Что такое ленивая загрузка в Angular и как ее применять
Ленивая загрузка - это техника, используемая в Angular для повышения производительности приложения путем загрузки модулей только тогда, когда они...
1
3
795
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы можете сделать что-то вроде этого:

type Key = `data-element-${1|2|3|4|5|6|7|8|9|0}`

const obj:Record<Key, string> = {
    'data-element-0': 'something',
    'data-element-1': 'something else',
    'data-element-2': 'something as well',
    'data-element-3': 'something to feel included',
    'data-element-yu': 'something to feel included', // error
};

ОБНОВЛЯТЬ Я также сделал помощников для двойных чисел, от: 0-99:

type NonZeroDigit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'

type NumberHelper = {
  [P in NonZeroDigit]: {
    [Z in NonZeroDigit]: `${P}${Z}`
  }
}

type NestedValues<T extends Record<string, Record<string, string>>> = {
  [P in keyof T]: P extends string ? Values<T[P]> : never
}
type Values<T> = T[keyof T]

type RemoveTrailingZero<T extends string> = T extends `${infer Fst}${infer Snd}` ? Fst extends `0` ? `${Snd}` : `${Fst}${Snd}` : never;

type Numbers_99 = RemoveTrailingZero<Values<NestedValues<NumberHelper>>>

ОБНОВЛЯТЬ

Здесь у вас есть утилита для генерации диапазона чисел от 0 до 99999.

type Values<T> = T[keyof T]

type LiteralDigits = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
type NumberString<T extends number> = `${T}`

type AppendDigit<T extends number | string> = `${T}${LiteralDigits}`

type MakeSet<T extends number> = {
    [P in T]: AppendDigit<P>
}

type RemoveTrailingZero<T extends string> = T extends `${infer Fst}${infer Rest}` ? Fst extends `0` ? RemoveTrailingZero<`${Rest}`> : `${Fst}${Rest}` : never;

type From_1_to_999 = RemoveTrailingZero<Values<{
    [P in Values<MakeSet<LiteralDigits>>]: AppendDigit<P>
}>>

type By<V extends NumberString<number>> = RemoveTrailingZero<Values<{
    [P in V]: AppendDigit<P>
}>>

type From_1_to_99999 =
    | From_1_to_999
    | By<From_1_to_999>
    | By<From_1_to_999
        | By<From_1_to_999>>

Демо

ОБНОВЛЕНИЕ 3

Если вы все еще хотите генерировать буквенные числа, а не строковые числа, вы можете использовать этот код, который был беззастенчиво украден из здесь

type PrependNextNum<A extends Array<unknown>> = A['length'] extends infer T ? ((t: T, ...a: A) => void) extends ((...x: infer X) => void) ? X : never : never;

type EnumerateInternal<A extends Array<unknown>, N extends number> = { 0: A, 1: EnumerateInternal<PrependNextNum<A>, N> }[N extends A['length'] ? 0 : 1];

type Enumerate<N extends number> = EnumerateInternal<[], N> extends (infer E)[] ? E : never;

type Result = Enumerate<43> // 0 | 1 | 2 | ... | 42

*ОБНОВЛЕНИЕ от 8 сентября 2021 г.

Начиная с TS 4.5, см. Хвостовая рекурсия PR, можно генерировать гораздо более длинный диапазон чисел.

См. пример:

type MAXIMUM_ALLOWED_BOUNDARY = 999

type ComputeRange<
    N extends number,
    Result extends Array<unknown> = [],
    > =
    (Result['length'] extends N
        ? Result
        : ComputeRange<N, [...Result, Result['length']]>
    )

const ComputeRange = (N: number, Result: number[] = []): number[] => {
    if (Result.length === N) {
        return Result
    }
    return ComputeRange(N, [...Result, Result.length])
}
// 0 , 1, 2 ... 998
type NumberRange = ComputeRange<MAXIMUM_ALLOWED_BOUNDARY>[number]

Попутный вопрос

Детская площадка

Я пытаюсь понять, как сделать это для двойного числа, например: 10|11|12|13 ....

captain-yossarian from Ukraine 15.12.2020 15:37

Вы можете сделать это как это, но я не уверен, соответствует ли это варианту использования или нет. Если OP заботится о пробелах или хочет иметь неограниченный максимальный размер, тогда он становится более волосатым.

jcalz 15.12.2020 15:48

Также есть data-element-${number}, но он принимает нецелые числовые значения. Положительным моментом является отсутствие встроенного максимального значения или огромного типа объединения.

jcalz 15.12.2020 17:13

Другие вопросы по теме