EdF*_*EdF 7 javascript typescript typescript-generics
I have a generic function that reads or writes the caller-chosen property of a given object. I'm using type constraints to ensure that the key passed is for a property that is assignable to or from the relevant type. Calling code appears to typecheck correctly. The usage of the object's property within the implementation does not typecheck as expected.
In this example I use boolean as the expected type. I've commented the lines that are not typechecking as expected. You can also see this example in the typescript playground here.
How can I express the signature of booleanAssignmentTest so that the typechecker understands obj[key] has type boolean? Can it be done in a fashion that keeps the boolean itself generic to allow multiple such similar functions, that work with other types, to be defined uniformly?
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!
Run Code Online (Sandbox Code Playgroud)
我正在使用tsc3.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!
Run Code Online (Sandbox Code Playgroud)
第一个选项(使用KeysOfPropertiesWithType)不起作用,因为打字稿无法推理仍然包含未解析类型参数的条件类型(例如T和K在本例中)
第二个选项不起作用,因为例如T extends Record<K, boolean>手段可能意味着分配无效。通常,必须扩展类型的事实并不意味着我们可以在泛型函数内部为其分配任何值,约束只是告诉我们该值的最低要求是什么,我们还不知道完整的契约T{ a: false }obj[key] = trueT[K]T[K]要求。
至少对您的示例代码有效的解决方案是根本不使用T。在这种情况下似乎没有必要:
function booleanAssignmentTest2<K extends PropertyKey>(obj: Record<K, boolean>, key: K): void {
let foo: boolean = obj[key]; // Fine!
let foo2: string = obj[key]; // Error: working as intended!
obj[key] = true; // Ok now we know T[K] is boolean
}
let foo = { aBool: false, aNumber: 33, anotherBool: false };
booleanAssignmentTest2(foo, "aBool"); // Fine!
booleanAssignmentTest2(foo, "anotherBool"); // Fine!
booleanAssignmentTest2(foo, "aNumber"); // Error: working as intended!
Run Code Online (Sandbox Code Playgroud)
如果您的示例更复杂,请提供完整示例,尽管如果您确定该值可分配给T[K],通常解决方案将使用类型断言,因此这是一个可能的解决方案:
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 as T[K]; // ok now
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
164 次 |
| 最近记录: |