enum Animals {
CAT,
DOG,
PARROT,
SHEEP,
SALMON
}
Следующий тип:
type AnimalsToMappedType = {
[K in keyof typeof Animals]: K
}
Результаты:
type AnimalsToMappedType = {
readonly [x: number]: number;
readonly CAT: "CAT";
readonly DOG: "DOG";
readonly PARROT: "PARROT";
readonly SHEEP: "SHEEP";
readonly SALMON: "SALMON";
}
Но если вы добавите круглые скобки вокруг keyof typeof Animals
:
type AnimalsToMappedType = {
[K in (keyof typeof Animals)]: K
}
Результат:
type AnimalsToMappedType = {
CAT: "CAT";
DOG: "DOG";
PARROT: "PARROT";
SHEEP: "SHEEP";
SALMON: "SALMON";
}
ВОПРОС
Что делают скобки, которые удаляют readonly [x: number]: number;
?
@jcalz это было намного яснее, прежде чем кто-то решил взять на себя задачу отредактировать это
Хм, я все еще вижу там несколько вопросов. Какой у вас главный вопрос?
Спасибо. Без скобок это гомоморфный отображаемый тип, где TS распознает, что вы выполняете итерацию по «всем свойствам typeof Animals
»; в каком-то смысле in keyof
— это отдельная синтаксическая единица. В случае круглых скобок он не является гомоморфным и просто перебирает все ключи, содержащиеся в выражении. Числовые объекты-перечисления имеют обратные сопоставления в своем типе (и сигнатуру числового индекса), но number
не включен в keyof typeof Animals
. Отсюда и разница. Это полностью решает вопрос? Если да, то я напишу полную а; если нет, то чего не хватает?
(см. предыдущий комментарий...github.com/microsoft/TypeScript/issues/40206 является канонической проблемой для этого, кстати, я включу это в свой ответ, если вы согласны, что он полностью решает вопрос)
См. microsoft/TypeScript#40206 для получения авторитетного ответа.
Сопоставленный тип формы {[K in keyof XXX]: YYY}
считается гомоморфным отображаемым типом , где TypeScript видит in keyof
и распознает, что вы преобразуете какой-то другой тип XXX
, и поэтому может использовать информацию об исходном типе, которого нет. в результатах keyof. С другой стороны, отображаемый тип подобного вида {[K in (keyof XXX)]: YYY}
не считается гомоморфным. Круглые скобки заставляют TypeScript сначала вычислять keyof XXX
, а затем отображаемые типы перебирают эти результаты, ничего не зная и не помня о XXX
. Итак, in keyof XXX
хранит информацию о XXX
вокруг того, что in (keyof XXX)
выбрасывает.
Эта разница чаще всего наблюдается при преобразовании типа со свойствами необязательных и только для чтения. Гомоморфный отображаемый тип сохранит необязательный /readonly
, даже если такая информация не видна через keyof
. Например, если XXX
равно {a?: string, readonly b: number}
, то {[K in keyof XXX]: YYY}
будет производить {a?: YYY, readonly b: YYY}
, тогда как {[K in (keyof XXX): YYY}
будет производить {a: YYY, b: YYY}
.
В вашем примере вы работаете с объектом числового перечисления , который имеет обратные сопоставления . Если Animals.CAT === 0
, то Animals[0] === "CAT"
. TypeScript моделирует это, добавляя числовую подпись индекса к объекту перечисления, но эта подпись индекса подавляется при использовании keyof
. Таким образом, хотя typeof Animals
может выглядеть как { [k: number]: string; CAT: 0 }
, keyof typeof Animals
— это просто "CAT"
, а не number | "CAT"
. Таким образом, гомоморфный отображаемый тип для числового перечисления будет иметь числовую сигнатуру индекса, тогда как негомоморфный отображаемый тип для числового перечисления не будет.
Пожалуйста, отредактируйте, чтобы четко задать один четко сформулированный вопрос. Сейчас это выглядит как несколько вопросов, большая часть которых выглядит как проблема XY, поскольку у вас есть некоторый базовый вариант использования (написание сопоставленного типа), и ваши вопросы касаются неудачных попыток. Если вы спрашиваете об основном варианте использования, я бы сказал, напишите
{ [K in string & keyof typeof Animals as typeof Animals[K]]: K }
. Если вы спрашиваете о поведении ваших попыток, задайте только один вопрос об одной такой попытке, а остальные разбейте на собственные вопросы, если они останутся после получения ответа на этот вопрос.