涉及泛型对象泛型属性的赋值无法在泛型函数中正确类型检查

编程入门 行业动态 更新时间:2024-10-27 16:29:08
本文介绍了涉及泛型对象泛型属性的赋值无法在泛型函数中正确类型检查的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

限时送ChatGPT账号..

我有一个通用函数,可以读取或写入给定对象的调用者选择的属性.我正在使用类型约束来确保传递的键用于可分配给相关类型或从相关类型分配的属性.调用代码似乎可以正确进行类型检查.实现中对象属性的使用未按预期进行类型检查.

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.

在本例中,我使用 boolean 作为预期类型.我已经评论了未按预期进行类型检查的行.您也可以在此处的打字稿游乐场中看到此示例.

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.

如何表达booleanAssignmentTest 的签名,以便类型检查器理解obj[key] 的类型为boolean?能否以一种保持 boolean 本身通用的方式来完成,以允许统一定义多个与其他类型一起使用的类似函数?

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!

我使用的是 tsc 3.4.5 版,以防万一.

I'm using tsc Version 3.4.5 in case it's relevant.

更新:

我在类似问题上找到了以下答案:https://stackoverflow/a/52047487/740958

I found the following answer on a similar issue: https://stackoverflow/a/52047487/740958

我尝试应用他们的方法,它更简单,效果更好,但是 obj[key] = true; 语句仍然存在相同的问题.

I tried to apply their approach which is simpler and works a little better, however the obj[key] = true; statement still has the same issue.

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 上的这个 ^^ 示例.

推荐答案

第一个选项(使用 KeysOfPropertiesWithType)不起作用,因为 typescript 无法推理仍然包含未解析类型参数的条件类型(如本例中的 TK)

The first option (using KeysOfPropertiesWithType) does not work because typescript can't reason about conditional types that still contains unresolved type parameters (such as T and K in this example)

第二个选项不起作用,因为 T extends Record 意味着 T 例如可以是 { a: false }这意味着赋值 obj[key] = true 将无效.通常,T[K] 必须扩展类型这一事实并不意味着我们可以在泛型函数内部为其分配任何值,约束只是告诉我们该值的最低要求是什么,我们还不知道 T[K] 需要的完整合同.

The second option does not work because T extends Record<K, boolean> means T can for example be { a: false } which would mean the assignment obj[key] = true would not be valid. Generally, the fact that T[K] must extends a type does not mean that inside the generic function we can assign any value to it, the constraint just tells us what the minimum requirement is for the value, we don't yet know the full contract T[K] requires.

至少对您的示例代码有效的解决方案是根本不使用 T.在这种情况下似乎没有必要:

A solution that does work, at least for your sample code, is to not use T at all. It does not seem necessary in this context:

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!

如果你的例子更复杂,请提供一个完整的例子,尽管如果你确定值可以分配给T[K],通常解决方案将使用类型断言,所以这是一个可能的解决方案:

If your example is more complicated, please provide a full example, although generally the solution will be use a type assertion if you are sure the value is assignable to T[K], so this is a possible solution:

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
}

这篇关于涉及泛型对象泛型属性的赋值无法在泛型函数中正确类型检查的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

更多推荐

[db:关键词]

本文发布于:2023-04-29 09:33:09,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1187577.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:赋值   函数   属性   对象   正确

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!