После некоторого обширного тестирования я сделал следующие выводы:
Надеюсь, это поможет кому-то еще узнать, кто ищет информацию о файлах.
То, что вы видите, это запрос типа. Если вы индексируете тип объекта, вы получите тип этого свойства. Например:
type Foo = { foo: number }['foo'] // is number
Если вы индексируете, используя объединение нескольких свойств, вы получаете объединение всех типов свойств:
type FooBar = { foo: number, bar: string, baz: boolean }['foo' | 'bar'] // string | number
Если вы индексируете, используя все ключи, вы получаете объединение всех типов свойств:
type FooBarBaz = { foo: number, bar: string, baz: boolean }['foo' | 'bar' | 'baz'] // string | number | boolean
Но чтобы получить объединение всех имен свойств, вы можете использовать keyof
, поэтому приведенный выше тип также можно записать как:
type O = { foo: number, bar: string, baz: boolean }
type FooBarBaz = O[keyof O] // string | number | boolean
Тип { [K in keyof T]: K }
соответствует типу объекта, где ключи типизируются как один и тот же литеральный тип, представляющий ключ:
type O = { foo: number, bar: string, baz: boolean }
type FooBarBaz = { [K in keyof O]: K } // { foo: "foo"; bar: "bar"; baz: "baz"; }
Условный тип делает некоторые из этих ключей не одинаковыми. как литеральный тип, представляющий ключ, но вместо этого печатает их как never
:
type O = { foo: number, bar: string, baz: () => boolean } // baz is a function now
type NonFunctionPropertyNames = { [K in keyof O]: O[K] extends Function ? never: K } // { foo: "foo"; bar: "bar"; baz: never; }
Таким образом, новый тип по-прежнему имеет все ключи оригинала, но некоторые типизированы как литеральный тип соответствующего ключ, а некоторые набраны как never
. Нам нужно объединение со всеми типами значений ключей только что созданного нами типа, и мы можем использовать keyof O
, как и раньше (поскольку тип имеет те же ключи, что и O
):
type O = { foo: number, bar: string, baz: () => boolean } // baz is a function now
type NonFunctionPropertyNames = { [K in keyof O]: O[K] extends Function ? never: K }[keyof O] // "foo" | "bar" | never = "foo" | "bar" ;
never
всегда удаляется из объединений, поэтому в конце мы получаем объединение только тех объектных ключей, которые никогда не были.
Сделайте O
параметром типа, и у вас будет многоразовый тип для получения нефункциональных клавиш:
type NonFunctionPropertyNames<O> = { [K in keyof O]: O[K] extends Function ? never : K }[keyof O]
type Foo = { foo: number, bar: string, baz: () => boolean } // baz is a function now
type NonFUnctionKeysOfFoo = NonFunctionPropertyNames<Foo> // "foo" | "bar"