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

2024-06-28

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

在此示例中,我使用 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


第一个选项(使用KeysOfPropertiesWithType)不起作用,因为打字稿无法推理仍然包含未解析的类型参数的条件类型(例如T and K在这个例子中)

第二个选项不起作用,因为T extends Record<K, boolean> means T例如可以是{ a: false }这意味着分配obj[key] = true将无效。一般来说,事实是T[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!

如果您的示例更复杂,请提供完整的示例,但如果您确定该值可分配给,通常解决方案将使用类型断言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
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

涉及泛型对象的泛型属性的赋值无法在泛型函数内正确进行类型检查 的相关文章

随机推荐

  • Qt:如何制作二维插值颜色字段?

    我是 C 的初学者 尤其是与图形相关的 我想为我的图形视图制作一个动画背景 如下所示 梯度场气流 http www engineering leeds ac uk cfd research images untitled JPG 该图片表现
  • 在 Ruby 中生成正则表达式模式的字符串

    在Python语言中我发现rstr https bitbucket org leapfrogdevelopment rstr 可以生成一个字符串regex http en wikipedia org wiki Regular express
  • 如何解决转移/减少冲突?

    我正在使用 CUP 创建论文所需的解析器 我的语法中存在移位 归约冲突 我有这个生产规则 command IDENTIFIER IDENTIFIER LPAREN parlist RPAREN 我有这个警告 Warning Shift Re
  • 具有最大高度的 div 内的表格

    我想要一个可滚动的表格 为了实现这一点 我包装了一个 table into a div with a max height and overflow auto 除此之外 div has display inline block以确保 div
  • 在接收器上获取 Chromecast 发送器 URL

    Chromecast 接收者是否可以确定特定发送者的 URL 我可以获得发件人列表 const context cast framework CastReceiverContext getInstance context getSender
  • C++ win32 从资源加载字符串

    好吧 我最近决定将应用程序中的每个字符串放入 STRINGTABLE 中 这样我就可以轻松翻译成不同的语言 我知道如何使用 LoadString api 但这涉及我为要加载的每个字符串使用不同的变量 如果我的应用程序有 100 个字符串 那
  • 如何在颤动中设置容器的不透明度

    我想为包含十六进制颜色代码的容器设置不透明度 如何做呢 这是我当前的代码 final body Container width MediaQuery of context size width margin const EdgeInsets
  • 通过标记现有提交来触发 Jenkins 管道

    描述 我设置了 Jenkins 2 126 以便在推送新标签时构建管道 具体来说 我想将现有提交标记为master as release 3并让它触发构建 根据多个消息来源 我想要的是可能的 https mohamicorp atlassi
  • 在 java 中解析非常大的 XML 文档(以及更多)

    以下全部用Java编写 我必须构建一个应用程序 该应用程序将可能非常大的 XML 文档作为输入 该文档已加密 不是使用 XMLsec 而是使用我客户预先存在的加密算法 将分三个阶段进行处理 首先 将根据上述算法对流进行解密 其次 扩展类 由
  • PS3 上的 Mono 开发资源

    我一直在考虑冒险在我的 Playstation 3 上安装 Linux 由于 C 是我当前选择的语言 所以下一个合乎逻辑的步骤是安装 Mono 我做了一些研究发现http psubuntu com wiki InstallationInst
  • 合并两个 json 对象

    我有以下输入 2 个 json 文件 第一个是基本文件 第二个包含相同的属性但不同的值 我想合并这些对象 例如 a b asda c asdasd 第二个文件 a b d 结果应该是这样的 a b d c asdasd 用powershel
  • 正则表达式匹配句尾标记[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我需要匹配所有句末符号 例如 句点 等在给定的文本正文中 任何人都可以帮我解决正则表达式来做这样的事情吗 输入示例 This is t
  • 如何延迟从 ActiveMQ 在 Apache Camel 中消费消息

    我有一个要求 当客户端应用程序在 5 秒的时间范围内发送超过 1000 个请求时 我需要通过调整 排队 入站流量来进行限制 我遵循的解决方案是 我有一个camel throttle 将最大请求数设置为 1000 时间跨度设置为 5 秒 当超
  • C++:如何从 make_shared 部分推导模板参数

    为了规避对部分提供的显式模板参数的限制 https stackoverflow com questions 41833630 c17 class template partial deduction 我嵌入了要从中推导出类模板参数的结构 I
  • 反射的性能:JVM 中的高质量字节码

    Edit 2 是否有一个完全的程序object oriented实施能带来高性能吗 大部分的framework是用它的全部力量写的 然而 reflection也被大量用于实现它 例如AOP and dependency injection
  • Laravel - 在一个方法中返回多个值

    这是我目前陷入困境的地方 我正在执行多种方法 对同一个表进行不同的查询 public function totalOfA return a Stocks where user id this gt employee gt id gt whe
  • Javascript的removeChild()和appendChild() VS display=none和display=block|inline

    我正在开发一个 Web 应用程序 动态显示一些控件和描述 我不想使用 jQuery 或其他库 此时我使用以下方法使控件出现和消失 element setAttribute style display inline and element s
  • ASP.NET Identity 外部身份验证提供程序自定义图标

    使用 SimpleMembership 您可以向外部身份验证提供程序按钮添加一个图标 如下所示 简单会员制 Dictionary
  • 如何在 Julia 中实现迭代器?

    我正在尝试在 Julia 中实现迭代器 但是当 for 循环尝试调用时出现异常start已经 这是我得到的 我运行了 include 然后using RDF julia gt methods start 1 method for gener
  • 涉及泛型对象的泛型属性的赋值无法在泛型函数内正确进行类型检查

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