Авторитетный ответ для T0
можно найти в запросе на вытягивание , в котором реализованы «homomorphi c сопоставленные типы » или сопоставленные типы формы {[K in keyof T]: ...}
, где T
является параметром общего типа c. (Обратите внимание, что изначально он назывался «isomorphi c» вместо «homomorphi c», но это то же самое.)
Обычный вариант использования такого сопоставленного типа - это когда T
- некоторый тип объекта; в этом случае отображение сохраняет имена ключей из T
, а также их модификаторы «только для чтения» и «необязательности». (Можно переопределить эти модификаторы, явно установив их в сопоставленном типе.)
Итак, что происходит, когда T
является примитивным типом, например string
? В запросе на вытягивание говорится: «Мы просто создаем этот примитивный тип». Это оказывается очень полезным, особенно в случаях, когда вы рекурсивно используете сопоставленные типы. Тип, такой как
type DeepPartial<T> = { [K in keyof T]?: DeepPartial<T[K]> }
, будет проходить через тип вложенного объекта и делать каждое подсвойство необязательным ... и оставлять примитивы в покое :
declare const ab: DeepPartial<{ a: { b: string } }>;
const str = ab.a!.b!; // string
Это почти всегда то, чего хотят люди. Если бы такой тип продолжал возвращаться вниз по всем свойствам обернутых примитивов, таких как length
и toUpperCase
, вы бы получили в основном бесполезный тип. И тогда единственный способ получить "нормальную" версию - это использовать условные типы для завершения спуска вместо примитивов отображения:
type DeepPartial2<T> =
{ [K in keyof T]?: T[K] extends object ? DeepPartial2<T[K]> : T[K] }
, что менее удобно (и не так ли? Это возможно до тех пор, пока TS2.8 не представит условные типы).
В некотором смысле люди обычно хотят сохранить «ту же общую форму» для объектов, отображаемых гомоморфно, но то, что означает «та же общая форма», не всегда очевидно. Типы объектов остаются типами объектов. Примитивы остаются примитивами. Первоначально массивы рассматривались как обычные типы объектов, создавая почти бесполезный тип, который преобразовывал методы массива во что-то неузнаваемое. Это никому не понравилось, поэтому TypeScript 3.1 изменил его , так что сопоставленные типы массивов по-прежнему являются типами массивов, а сопоставленные типы кортежей по-прежнему являются типами кортежей.
Остается T1
, где отображение homomorphi c по свойствам any
дает индексируемый тип.
Ранее связанный запрос на вытягивание не go в него, но разработчик объяснил свои рассуждения в комментарии к проблеме GitHub , сообщив об этом как об ошибке:
keyof any
равно string | number | symbol
, поэтому сопоставленный тип, примененный к any
, дает эквивалент { [x: string]: XXX }
.
Обратите внимание, что он говорит «эквивалент». symbol
автоматически удаляется из сопоставленных типов, поэтому {[K in "a" | symbol]: string}
дает {a: string}
. Вам разрешено иметь индексы string
и number
по отдельности, поэтому {[K in string | number]: string}
равно {[k: string]: string; [k: number]: string}
. Но поскольку ключи numeri c считаются строковыми в TypeScript и JavaScript, это то же самое, что {[k: string]: string}
. (Если вы хотите узнать больше о том, что происходит с ключами string
, number
и symbol
при сопоставлении, вы можете увидеть эту документацию .)
Лично я Я не на 100% на борту с keyof any
, сопоставленным только с string
индексом вместо string
и number
, поскольку {[K in keyof T]: K}
покажет разницу ... но это второстепенный момент.
Важный момент взят из оставшейся части комментария:
Вы можете возразить, что мы должны просто дать any
, когда сопоставленный тип homomorphi c применяется к any
, но это было бы менее точно. Например, { [K in keyof T]: number }
, созданный с помощью T
, поскольку any
действительно должен давать { [x: string]: number }
, а не только any
.
Итак, поехали; any
рассматривается как тип объекта с ключами, индексируемыми строкой, так что сопоставление с ним дает что-то разумное. И этот комментарий является наиболее близким к каноническому ответу на этот вопрос, который я видел.
Хорошо, надеюсь, что это поможет; удачи!
Детская площадка ссылка на код