没有函数的接口和类型的类型实参推断

时间:2019-11-20 04:53:16

标签: typescript generics

在此示例中,我希望表达式property中的itemKV1属性受到约束,因此当propertyage时,value只能是number的类型。

关于如何做这样的事情的任何想法?

我知道如何使用函数中的泛型来执行此操作,因为它提供了here中所述的type argument inference

问题是我无法推断property来约束value。我不知道使用接口或类型执行此操作的方法。

interface Item {
  id: string;
  name: string;
  age: number;
}

// Where can I add a generic for `keyof T`?
type KV<T> = { property: keyof T; value: T[keyof T] };

// I want value to be of type `number`, not `string | number`
// this should show an error, but doesn't.
const itemKV1: KV<Item> = {
  property: "age",
  value: "not a number!"
};

// This should not error and doesn't.
const itemKV2: KV<Item> = {
  property: "age",
  value: 82
};

1 个答案:

答案 0 :(得分:1)

通常不可能同时推断和约束变量的类型。您可以在注释中指定类型,也可以让编译器根据分配来推断类型。

但是对于您的特定情况,还有另一种解决方案来使您想要的分配出现错误。您可以生成所有可能的property / value组合的并集。

interface Item {
  id: string;
  name: string;
  age: number;
}

// Where can I add a generic for `keyof T`?
type KV<T> = {
    [P in keyof T]: { property: P; value: T[P] };
}[keyof T]

// KV<Item> =  
//   | { property: "id"; value: string; }
//   | { property: "name"; value: string; }
//   | { property: "age"; value: number; }
// Error value is not numebr 
const itemKV1: KV<Item> = {
  property: "age",
  value: "not a number!"
};

// ok
const itemKV2: KV<Item> = {
  property: "age",
  value: 82
};

Playground Link

注意itemKV1.value仍将是string | number类型,除非您根据property字段将其缩小。如果希望变量的最终类型基于分配但受约束,则需要一个函数:

function property<T>() {
    return function <TKV extends KV<T>>(o: TKV) {
        return o 
    }
}

// ok
// const itemKV2: {
//     property: "age";
//     value: number;
// }
const itemKV2 = property<Item>()({
    property: "age",
    value: 82
});

Playground Link