【问题标题】:Typescript generics keyof doesn't match type打字稿泛型 keyof 与类型不匹配
【发布时间】:2022-01-18 11:03:19
【问题描述】:

我有这个接口,它只存储另一个接口的键(modelKey)和该键的值(value):

interface ValueHolder<T, H extends keyof T> {
  modelKey: H;
  value: T[H];
}

现在我想存储来自以下模型的horsePower,匹配类型在ValueHolder

interface Car {
  id: number;
  horsePower?: number;
  date: Date;
};

看起来像这样:

const test: ValueHolder<Car, keyof Car> = {
  modelKey: 'horsePower',
  value: 1000,
};

此时不会发生错误,它会很好地存储值。但你也可以传递Date 类型的值:

const test: ValueHolder<Car, keyof Car> = {
  modelKey: 'horsePower',
  value: new Date(),
};

因为无论出于何种原因,该值都可以接受所提供模型中所有类型的任何键:

(property) ValueHolder&lt;Car, keyof Car&gt;.value: string | number | Date | undefined


如果您提供modelKey horsePower,如何使接口ValueHoldervalue 键只接受undefined | number 类型的值?

Demo

【问题讨论】:

    标签: typescript typescript-generics


    【解决方案1】:

    ValueHolder 第二个通用参数 H 允许所有键,这反过来又导致允许所有值。

    您需要稍微修改您的主要实用程序类型以使非法状态无法表示。

    考虑这个例子:

    type Values<T> = T[keyof T]
    
    type ValueHolder<T> = Values<{
      [Prop in keyof T]: {
        modelKey: Prop;
        value: T[Prop]
      }
    }>
    
    // type Test = {
    //     modelKey: "id";
    //     value: number;
    // } | {
    //     modelKey: "horsePower";
    //     value: number | undefined;
    // } | {
    //     modelKey: "date";
    //     value: Date;
    // } | undefined
    type Test = ValueHolder<Car>
    
    interface Car {
      id: number;
      horsePower?: number;
      date: Date;
    };
    
    // ok
    const test: ValueHolder<Car> = {
      modelKey: 'horsePower',
      value: 1000,
    };
    
    // error 
    const test2: ValueHolder<Car> = {
      modelKey: 'horsePower',
      value: new Date(),
    };
    

    Playground

    type TestValueHolder 创建所有允许值的联合。它遍历每个键并创建此接口 {Prop:{modelKey:P, value:T[P]}}。然后Values 得到每个对象值{modelKey:P, value:T[P]} 并将它们联合起来。

    更新

    谢谢,工作正常!如果我希望T[Prop] 只能是字符串类型怎么办?也可以吗?

    是的。有两种方法可以实现它。您可以只允许ValueHolder 接收值为字符串的对象。

    type ValueHolder<T extends Record<string, string>> = Values<{
      [Prop in keyof T]: {
        modelKey: Prop;
        value: T[Prop]
      }
    }>
    

    或者,您可以检查内部迭代 T[Prop] 是否为字符串。

    type ValueHolder<T> = Values<{
      [Prop in keyof T]: T[Prop] extends string ? {
        modelKey: Prop;
        value: T[Prop]
      } : never
    }>
    

    【讨论】:

    • 谢谢,工作正常!如果我希望T[Prop] 只能是string 类型怎么办?这也可能吗?
    • @dewey 进行了更新
    猜你喜欢
    • 1970-01-01
    • 2022-08-21
    • 1970-01-01
    • 1970-01-01
    • 2021-11-26
    • 2010-09-20
    • 2020-08-13
    • 2015-04-09
    • 1970-01-01
    相关资源
    最近更新 更多