我有一个通用函数,可以读取或写入给定对象的调用者选择的属性。我使用类型约束来确保传递的键适用于可分配给相关类型或从相关类型分配的属性。调用代码的类型检查似乎正确。实现中对象属性的使用不会按预期进行类型检查。
在此示例中,我使用 boolean 作为预期类型。我已经评论了未按预期进行类型检查的行。您还可以在此处的打字稿游乐场中看到此示例。 https://www.typescriptlang.org/play/#src=type%20KeysOfPropertiesWithType%3CT%2C%20U%3E%20%3D%20%7B%0D%0A%20%20%2F%2F%20We%20check%20extends%20in%20both%20directions%20to%20ensure%20assignment%20could%20be%20in%20either%20direction.%0D%0A%20%20%5BK%20in%20keyof%20T%5D%3A%20T%5BK%5D%20extends%20U%20%3F%20(U%20extends%20T%5BK%5D%20%3F%20K%20%3A%20never)%20%3A%20never%3B%0D%0A%7D%5Bkeyof%20T%5D%3B%0D%0A%0D%0Atype%20PickPropertiesWithType%3CT%2C%20U%3E%20%3D%20Pick%3CT%2C%20KeysOfPropertiesWithType%3CT%2C%20U%3E%3E%3B%0D%0A%0D%0Afunction%20booleanAssignmentTest%3CT%20extends%20PickPropertiesWithType%3CT%2C%20boolean%3E%2C%20K%20extends%20KeysOfPropertiesWithType%3CT%2C%20boolean%3E%3E(obj%3A%20T%2C%20key%3A%20K)%3A%20void%20%7B%0D%0A%20%20%20%20let%20foo%3A%20boolean%20%3D%20obj%5Bkey%5D%3B%20%2F%2F%20Fine!%0D%0A%20%20%20%20let%20foo2%3A%20string%20%3D%20obj%5Bkey%5D%3B%20%2F%2F%20No%20error%2C%20but%20there%20should%20be!%0D%0A%20%20%20%20obj%5Bkey%5D%20%3D%20true%3B%20%2F%2F%20Error%3A%20%22Type%20'true'%20is%20not%20assignable%20to%20type%20'T%5BK%5D'.%22%0D%0A%7D%0D%0A%0D%0Alet%20foo%20%3D%20%7B%20aBool%3A%20false%2C%20aNumber%3A%2033%2C%20anotherBool%3A%20false%20%7D%3B%0D%0AbooleanAssignmentTest(foo%2C%20%22aBool%22)%3B%20%2F%2F%20Fine!%0D%0AbooleanAssignmentTest(foo%2C%20%22anotherBool%22)%3B%20%2F%2F%20Fine!%0D%0AbooleanAssignmentTest(foo%2C%20%22aNumber%22)%3B%20%2F%2F%20Error%3A%20working%20as%20intended!%0D%0A
我该如何表达签名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(如果相关)。
Update:
我在类似问题上找到了以下答案:https://stackoverflow.com/a/52047487/740958 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 上的示例。 https://www.typescriptlang.org/play/#src=function%20booleanAssignmentTest2%3CT%20extends%20Record%3CK%2C%20boolean%3E%2C%20K%20extends%20keyof%20T%3E(obj%3A%20T%2C%20key%3A%20K)%3A%20void%20%7B%0D%0A%20%20%20%20let%20foo%3A%20boolean%20%3D%20obj%5Bkey%5D%3B%20%2F%2F%20Fine!%0D%0A%20%20%20%20let%20foo2%3A%20string%20%3D%20obj%5Bkey%5D%3B%20%2F%2F%20Error%3A%20working%20as%20intended!%0D%0A%20%20%20%20obj%5Bkey%5D%20%3D%20true%3B%20%2F%2F%20Error%3A%20%22Type%20'true'%20is%20not%20assignable%20to%20type%20'T%5BK%5D'.%22%0D%0A%7D%0D%0A%0D%0Alet%20foo%20%3D%20%7B%20aBool%3A%20false%2C%20aNumber%3A%2033%2C%20anotherBool%3A%20false%20%7D%3B%0D%0A%0D%0AbooleanAssignmentTest2(foo%2C%20%22aBool%22)%3B%20%2F%2F%20Fine!%0D%0AbooleanAssignmentTest2(foo%2C%20%22anotherBool%22)%3B%20%2F%2F%20Fine!%0D%0AbooleanAssignmentTest2(foo%2C%20%22aNumber%22)%3B%20%2F%2F%20Error%3A%20working%20as%20intended!%0D%0A