我想写一个indexByProp
函数,它将要索引的道具的选择限制为那些可索引的值(字符串、数字、符号(。
此问题是 https://github.com/microsoft/TypeScript/issues/33521 的延续。到目前为止,我尝试构建此功能的尝试可以在此 TS Playground 链接中找到。
我期望的结果是,例如:
indexByProp('bar', [{ // should be ok
bar: 1,
foo: '2',
qux: () => {}
}])
indexByProp('qux', [{ // should be type error
bar: 1,
foo: '2',
qux: () => {}
}])
您正在寻找类似以下内容:
type KeysMatching<T, V> = NonNullable<
{ [K in keyof T]: T[K] extends V ? K : never }[keyof T]
>;
其中KeysMatching<T, V>
为您提供属性可分配给V
的T
的键。 它查找映射的条件类型的属性值来执行此操作。 一个示例来说明它是如何工作的:
interface Foo {
a?: string;
b: number;
}
// give me all the keys of Foo whose properties are assignable to
// string | undefined... expect to get "a" back
type Example = KeysMatching<Foo, string | undefined>;
这是这样评估的:
type Example2 = NonNullable<
{
a?: Foo["a"] extends string | undefined ? "a" : never;
b: Foo["b"] extends string | undefined ? "b" : never;
}["a" | "b"]
>;
type Example3 = NonNullable<
{
a?: string | undefined extends string | undefined ? "a" : never;
b: number extends string ? "b" : never;
}["a" | "b"]
>;
type Example4 = NonNullable<{ a?: "a"; b: never }["a" | "b"]>;
type Example5 = NonNullable<"a" | undefined | never>;
type Example6 = NonNullable<"a" | undefined>;
type Example7 = "a";
这给了"a"
如预期的那样。
然后,IndexableKeys
只是:
type IndexableKeys<T> = KeysMatching<T, keyof any>;
您的indexByProp()
函数如下所示:
const indexByProp = <X extends Indexable>(
propName: IndexableKeys<X>,
xs: X[]
): Indexable<X> => {
const seed: Indexable<X> = {};
return xs.reduce((index, x) => {
const address = x[propName];
index[address as keyof typeof index] = x; // need assertion
return index;
}, seed);
};
并且您的测试按预期运行:
indexByProp("bar", [
{
bar: 1,
foo: "2",
qux: () => {}
}
]); // okay
indexByProp("qux", [
// ~~~~~ error!
// Argument of type '"qux"' is not assignable to parameter of type '"bar" | "foo"'.
{
// should be type error
bar: 1,
foo: "2",
qux: () => {}
}
]);
希望有帮助;祝你好运!
链接到代码