Текущий тип возврата (string[]
) является преднамеренным. Почему?
Рассмотрим такой тип:
interface Point {
x: number;
y: number;
}
Вы пишете такой код:
function fn(k: keyof Point) {
if (k === "x") {
console.log("X axis");
} else if (k === "y") {
console.log("Y axis");
} else {
throw new Error("This is impossible");
}
}
Давайте зададим вопрос:
Может ли законный вызов fn
в хорошо напечатанной программе вызвать ошибку?
желаемый ответ, конечно же, "Нет". Но какое это имеет отношение к Object.keys
?
Теперь рассмотрим этот другой код:
interface NamedPoint extends Point {
name: string;
}
const origin: NamedPoint = { name: "origin", x: 0, y: 0 };
Обратите внимание, что в соответствии с системой типов TypeScript все NamedPoint
с действительны Point
с.
Теперь давайте напишем немного больше кода :
function doSomething(pt: Point) {
for (const k of Object.keys(pt)) {
// A valid call iff Object.keys(pt) returns (keyof Point)[]
fn(k);
}
}
// Throws an exception
doSomething(origin);
Наша хорошо напечатанная программа только что вызвала исключение!
Что-то пошло не так!
Возвращая keyof T
из Object.keys
, мы нарушили предположение, что keyof T
образует исчерпывающий список, потому что наличие ссылки на объект не означает, что тип ссылки не является t супертип типа значения .
В принципе, (по крайней мере) одна из следующих четырех вещей не может быть правдой:
keyof T
- исчерпывающий список клавиш T
- Тип с дополнительными свойствами всегда является подтипом своего базового типа
- Допустимо псевдоним значения подтипа ссылкой на супертип
Object.keys
возврат keyof T
Точка отбрасывания 1 делает keyof
почти бесполезной, поскольку подразумевает, что keyof Point
может быть некоторым значением, которое не "x"
или "y"
.
Точка отбрасывания 2 полностью разрушает систему типов TypeScript. Не вариант.
Удаление точки 3 также полностью разрушает систему типов TypeScript.
Отбрасывание пункта 4 - это хорошо, и вы, программист, должны подумать о том, является ли объект, с которым вы имеете дело, псевдонимом для подтипа того, что, по вашему мнению, у вас есть.
«Отсутствующая функция», делающая это легальным, но не противоречивым , является Точными типами , что позволит вам объявить новый тип типа, который не был не подпадает под пункт № 2. Если бы эта функция существовала, предположительно было бы возможно сделать Object.keys
return keyof T
только для T
s, которые были объявлены как точные .