繁体   English   中英

如何在打字稿中扩展记录类型的键

[英]How to extend the Record type's keys in typescript

这是打字稿中的预期行为吗?

const NeedsRecord = <T extends Record<string, any>>(record: T) => {}

NeedsRecord({
    5: "🚨 Should error, doesn't 🚨"
});

我想通过继承来限制Record键类型的类型。 我怎样才能做到这一点?

将键类型作为泛型参数也不能按预期工作:

const NeedsRecord = <T extends string>(record: Record<T, any>) => { }

NeedsRecord({
    5: "🚨 Should error, doesn't 🚨"
});

显式定义联合键类型有效,但使用起来很难看:

const NeedsRecord = <T extends string>(record: Record<T, any>) => { }

NeedsRecord<"a"|"b">({
    a: "works",
    b: "works",
    // 5: "🚨 fails properly"
    // c: "🚨 fails properly"
});

这是预期的 TypeScript 行为。 “数字”对象键实际上是字符串,因此,TypeScript 将字符串索引签名视为支持数字甚至符号键

如果要强制编译器在传递number值键时产生错误,可以这样做:

const needsRecord = <T extends { [K in keyof T]: K extends number ? never : any }>(
  record: T
) => { }

needsRecord({
  a: "works",
  b: "works",
  5: "error" // string is not assignable to never
});

但要注意......在 JavaScript 中, {5: ""}{"5": ""}之间真的没有区别,因为键被强制转换为字符串:

const oN = { 5: "" };
console.log(typeof (Object.keys(oN)[0])); // "string"
const oS = { "5": "" };
console.log(JSON.stringify(oS) === JSON.stringify(oN)); // true

这意味着上面的needsRecord()会认为这很好:

needsRecord({
  a: "works",
  b: "works",
  "5": "oops" // no error
})

但是没有充分的理由允许一个而不允许另一个。 而且 TypeScript 目前没有很好的内置方法来排除“类似数字的字符串”,所以我不确定您可以在这里做更多的事情。

鉴于5"5"作为键是相同的,你为什么真正关心禁止这个? 对于您的用例,TypeScript 的预期行为是否可能实际上是可以接受的? 或者,如果您允许使用数字键,真的会出错吗?

Playground 链接到代码

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM