【问题标题】:How to extend the Record type's keys in typescript如何在打字稿中扩展记录类型的键
【发布时间】:2020-10-13 20:27:52
【问题描述】:

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

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


    【解决方案1】:

    这是预期的 TypeScript 行为。 “数字”对象键是 actually strings,因此 TypeScript 将字符串索引签名视为 supporting number and even symbol keys

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

    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 link to code

    【讨论】:

    • 感谢您的解释。有了你的信息,我意识到我可以扩展我的用例以允许字符串/数字/符号联合,而不是试图将键限制为仅字符串。
    猜你喜欢
    • 2014-06-11
    • 2020-08-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-26
    • 1970-01-01
    相关资源
    最近更新 更多