打字稿:按与自身值匹配的接口属性进行类型过滤



想要从第一个参数为第二个参数创建过滤类型

请检查以下代码:

interface TypeWithLabel {
label: string;
list: string;
}
interface A extends TypeWithLabel{
label: 'a';
list: '1' | '2' | '3';
}
interface B extends TypeWithLabel {
label: 'b';
list: '4' | '5' | '6';
}
type TypeProperty<T, U extends keyof T> = T[U];
function ab<T extends TypeWithLabel, U = TypeProperty<T, 'label'>>(
label: U,
item: TypeProperty<T, 'list'>
) {
}
// want to get A Only with label:'a'
// then display '1' | '2' | '3' for item
ab<A | B>('a', '1'); // correct
ab<A | B>('a', '4'); // error
// want to get B Only with label:'b'
// then display '4' | '5' | '6' for item
ab<A | B>('b', '4'); // correct
ab<A | B>('b', '1'); // error

也许,有没有另一种过滤接口的方法? 我想过如何重用泛型,但label函数中需要字符串值。

不确定,如果我理解正确 - 如果您希望函数ab的作用域为AB,那么您的泛型类型参数也应该反映此要求。您需要将代码更改为:

// given A, restrict item to '1' | '2' | '3'
ab<A>("a", "1"); // ok
ab<A>("a", "4"); // error (ok)
// given A, restrict item to '4' | '5' | '6'
ab<B>("b", "4"); // ok
ab<B>("b", "1"); // error (ok)

操场

上面的代码有一个轻微的缺点,即必须手动设置泛型类型参数。如果有一天U = TypeProperty<T, 'label'>无法再提供默认类型,则必须在每个涉及ab的代码位置添加U,并且无法推断。

另一种方法是创建查找类型LabelToList。如果您只有几个接口(如AB(以及许多ab调用,则这种风格是有利的。可以通过对示例进行如下编码来省略手动泛型类型参数:

type LabelToList = {
a: A;
b: B;
};
function ab<K extends keyof LabelToList>(
label: K,
item: LabelToList[K]["list"]
) {}

操场

最新更新