根据泛型类型中的值的类型来约束键

时间:2021-05-21 09:42:56

标签: typescript typescript-generics

我正在尝试编写一个泛型函数,其中使用泛型类型来键入其参数。

这是这个参数的一部分:

type Configuration<T> = {
    masterdata: T[],
    target: ????
}

我在输入 target 属性时遇到问题。我希望它是特定类(MtmFormComponent,当前类)中的任何属性的名称,但具有属性类型为 T[] 的约束。

我的目标是写:this[configuration.target] = configuration.masterdata;

我已经到了一半。以下是我现在输入 target 的方式:

type MtmFormComponentPropertyOfType<T, K extends keyof MtmFormComponent> = MtmFormComponent[K] extends T[] ? K : never;

type DropdownAutocompleteConfiguration<T, K extends keyof MtmFormComponent> = {
    masterdata: T[],

    targetFilteredList: MtmFormComponentPropertyOfType<T, K>,
};

在声明类型为 DropdownAutocompleteConfiguration 的对象时,一切都很好,并且我的 IDE 的自动完成功能正确地限制了我只使用导致与 masterdata 的值相同类型的键。所以我的类型似乎定义正确。

我的问题是在我的通用函数中使用该对象时:

private setupDropdownAutocompleteBehaviour<T, K extends keyof MtmFormComponent>(configuration: DropdownAutocompleteConfiguration<T, K>): void {
        this[configuration.targetFilteredList] = configuration.masterdata;

        // ...
    }

此处,this[configuration.targetFilteredList] 表达式给出以下错误:

<块引用>

类型 'T[]' 不能分配给类型 'this[Currency[] extends T[] ? "filteredCurrencyList" : never] & this[PriceUnit[] extends T[] ? "filteredPriceUnits" : never] & this[Subscription[] extends T[] ? “订阅”:从不]'。
类型 'T[]' 不能分配给类型 'this[Currency[] extends T[] ? "filteredCurrencyList" : 从不]'.
类型“T[]”不可分配给类型“货币[]”。
“T”类型不能分配给“货币”类型。

据我了解,在函数内部,TypeScript 完全解析了 this[configuration.targetFilteredList] 的类型,而不是依赖于它是 T[] 的事实。从我的 IDE 的自动完成功能来看,我确信我不能拥有 target 的值,这会导致类型与 masterdata 之一不兼容。

我不知道从那里开始做什么:/

感谢您的帮助:)

1 个答案:

答案 0 :(得分:0)

在这种特殊情况下,您是否必须使您的函数在目标属性键上通用?

举个具体的例子,假设 MtmFormComponent 是这样定义的

interface MtmFormComponent {
    foo: string[];
    bar: string[];
    baz: number[];
    qux: string;
}

现在,我们想要一个类型,它为我们提供类型 T 的所有属性名称,其中属性名称映射到一个 U[] 值。我们可以这样定义这个类型:

type ArrayValuedProps<T, U> = { [K in keyof T]: (T[K] extends U[] ? K : never) }[keyof T]

这样,我们得到

ArrayValuedProps<MtmFormComponent, string> = { foo: "foo"; bar: "bar"; baz: never; qux: never }[keyof MtmFormComponent]
                                           = { foo: "foo"; bar: "bar"; baz: never; qux: never }["foo" | "bar" | "baz" | "qux"]
                                           = "foo" | "bar" | never
                                           = "foo" | "bar"

同理,ArrayValuedProps<MtmFormComponent, number> 等价于类型 "baz";

使用它,我们可以像这样定义您的 Configuration<T> 类型:

type Configuration<T> = {
    masterdata: T[],
    target: ArrayValuedProps<MtmFormComponent, T>
}

并且我们可以完全避免将目标键作为类型参数放入。