#typescript
#typescript
Вопрос:
Я пытаюсь создать условный тип в TypeScript, который различает типы «записей» (где ключи неограниченные / динамические) и простые типы объектов (где ключи предварительно определены).
type R = { [x: string]: any }
type O = { a: string; b: number }
Я могу получить ключи типов и проверить наличие некоторого, надеюсь, не существующего свойства:
type R = { [x: string]: any }
type O = { a: string; b: number }
type IsRecord<T> = '__NEVER__' extends keyof T ? true : false
type RR = IsRecord<R> // true
type OO = IsRecord<O> // false
Но это кажется хакерским. Возможно ли это более чистым способом?
Комментарии:
1. Является ли троичный в
'__NEVER__' extends keyof R ? true : false
необходимым? Если'__NEVER__' extends keyof R
возвращает aboolean
, это избыточно.2. В качестве альтернативы вы могли бы использовать
!!('__NEVER__' extends keyof O)
3. @AlexH в случае условных типов я считаю, что это необходимо. Но это был только псевдокод, я отредактировал пример, чтобы сделать его немного более понятным, надеюсь. Я ищу ответ, который не связан
__NEVER__
с тестом поддельного ключа.
Ответ №1:
string
Индексируемый тип можно определить, проверив, является ли string
он одним из его ключей:
type IsRecord<T> = string extends keyof T ? true : false
type RR = IsRecord<R> // true
type OO = IsRecord<O> // false
Да, вы можете сделать это так, как вы делали с поддельным ключом, но если вы беспокоитесь о «хакерстве», я бы предложил использовать string
вместо этого.
Обратите внимание, что существуют также number
индексируемые типы (например Array<any>
), и поскольку string
это не обязательно ключ number
индексируемого типа, они будут отображаться как не-запись:
type N = { [x: number]: any };
type NN = IsRecord<N>; // false
Если вам нужно идентифицировать оба string
и number
индексы как похожие на записи, достаточно проверить number
, поскольку, с точки зрения ключей, number
присваивается string
. (Это может сбить с толку, но поскольку все объекты JS фактически используют string
symbol
ключи or , всякий раз, когда вы индексируете объект с помощью a number
, он принудительно преобразуется в string
первый. arr[0]
и arr["0"]
это одно и то же. TypeScript поддерживает это, рассматривая все string
индексируемые типы как имеющие оба string
и number
в качестве своих ключей. Приведенная выше ссылка проходит через это):
type IsNumericIndex<T> = number extends keyof T ? true : false
type RRR = IsNumericIndex<R> // true
type OOO = IsNumericIndex<O> // false
type NNN = IsNumericIndex<N> // true
Комментарии:
1. Вау, так просто, но я об этом не подумал. Спасибо!