У меня есть универсальная функция, которая читает или записывает свойство выбранного объекта данного объекта.Я использую ограничения типа, чтобы гарантировать, что переданный ключ предназначен для свойства, которое присваивается соответствующему типу или от него.Код вызова, по-видимому, проверяется правильно.Использование свойства объекта в реализации не выполняет проверку типов, как ожидалось.
В этом примере я использую логический тип в качестве ожидаемого типа.Я прокомментировал строки, которые не проверяют тип, как ожидалось. Вы также можете увидеть этот пример на игровой площадке здесь.
Как я могу выразить подпись booleanAssignmentTest
, чтобы средство проверки типов понимало, что obj[key]
имеет тип boolean
?Можно ли сделать это таким образом, чтобы сам по себе boolean
был универсальным, чтобы позволить множеству подобных функций, работающих с другими типами, быть единообразно определенными?
type KeysOfPropertiesWithType<T, U> = {
// We check extends in both directions to ensure assignment could be in either direction.
[K in keyof T]: T[K] extends U ? (U extends T[K] ? K : never) : never;
}[keyof T];
type PickPropertiesWithType<T, U> = Pick<T, KeysOfPropertiesWithType<T, U>>;
function booleanAssignmentTest<T extends PickPropertiesWithType<T, boolean>, K extends KeysOfPropertiesWithType<T, boolean>>(obj: T, key: K): void {
let foo: boolean = obj[key]; // Fine!
let foo2: string = obj[key]; // No error, but there should be!
obj[key] = true; // Error: "Type 'true' is not assignable to type 'T[K]'."
}
let foo = { aBool: false, aNumber: 33, anotherBool: false };
booleanAssignmentTest(foo, "aBool"); // Fine!
booleanAssignmentTest(foo, "anotherBool"); // Fine!
booleanAssignmentTest(foo, "aNumber"); // Error: working as intended!
Я использую tsc
Версия3.4.5 на случай, если это уместно.
Обновление:
Я нашел следующий ответ на похожую проблему: https://stackoverflow.com/a/52047487/740958
Я пыталсяпримените их подход, который проще и работает немного лучше, однако оператор obj[key] = true;
все еще имеет ту же проблему.
function booleanAssignmentTest2<T extends Record<K, boolean>, K extends keyof T>(obj: T, key: K): void {
let foo: boolean = obj[key]; // Fine!
let foo2: string = obj[key]; // Error: working as intended!
obj[key] = true; // Error: "Type 'true' is not assignable to type 'T[K]'."
}
let foo = { aBool: false, aNumber: 33, anotherBool: false };
booleanAssignmentTest2(foo, "aBool"); // Fine!
booleanAssignmentTest2(foo, "anotherBool"); // Fine!
booleanAssignmentTest2(foo, "aNumber"); // Error: working as intended!
Этот пример ^^ на TS Playground.