【问题标题】:Generic parameter extending a record does not infer key type constraint扩展记录的通用参数不推断键类型约束
【发布时间】:2023-03-10 01:45:01
【问题描述】:

创建Record 时,keyof 会正确确定其密钥类型。但是当泛型参数扩展 Record 时,不会推断出键类型约束:

export type Dictionary<K extends number | string, V> = Partial<Record<K, V>>;

type MyDict = Dictionary<string, any>;
type Key = keyof MyDict; // Key correctly infered as string;

const myFunc = <D extends MyDict>(dict: D) => {
  // keyof D incorrectly infered as string | number | symbol 
  type OtherDict = Dictionary<keyof D, number>; 
};

playground link

有没有办法解决这个问题,并应用约束而不必断言每个 keyof D 实例的类型?

【问题讨论】:

    标签: typescript dictionary generics record type-inference


    【解决方案1】:

    编译器在技术上是正确的,D 可能具有symbol 值的键。 TypeScript 中的对象类型是开放的/可扩展的,而不是封闭的/精确的。 (有关确切类型的功能请求,请参阅microsoft/TypeScript#12936)您可以将属性添加到对象类型并仍然符合该对象类型。这是一个示例,但它可能不太可能:

    const s = Symbol("symbol");
    interface YourDict extends MyDict {
      [s]: number;
    }
    const d: YourDict = { [s]: 123 };
    myFunc(d);
    

    YourDict 类型绝对是MyDict 的扩展,它有一个symbol 值的键。并且对myFunc() 的调用接受YourDict 类型的值。由于D 可能有任何键,因此编译器不愿在受限于string | number 的地方使用keyof D


    绕过这个问题的最简单的方法是在你的Dictionary 中只允许symbol 键,而不是试图梳理keyof D 以排除symbol

    export type Dictionary<K extends PropertyKey, V> = Partial<Record<K, V>>;
    

    PropertyKey 类型是 built in utility typestring | number | symbol 的同义词。这清除了错误:

    const myFunc = <D extends MyDict>(dict: D) => {
      type OtherDict = Dictionary<keyof D, number>; // okay
    };
    

    我的猜测是,这可能足以满足您的需求,因为我怀疑您根本不想花很多时间担心 symbol 键。如果你有一些重要的理由禁止symbol 或其他键,你可以采取一些步骤,但是 TypeScript 类型系统的开放类型使得这有点棘手,所以我不推荐它。

    Playground link to code

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-11-19
      • 2020-05-27
      • 2022-08-10
      • 2011-04-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多