【发布时间】:2022-01-26 19:57:46
【问题描述】:
我正在尝试提供一个帮助器/包装器函数 (get_item),它应该返回一个对象属性的单个项目,但不知何故我无法完成正确的输入。
// without typings
function get_item(foo, key, index) {
const array = foo[key];
// check if the index exists
if (index in array === false) throw new Error("Item " + index + " not found for " + key);
return array[index];
}
// usage example
const item = get_item({bar:[0,1,2]}, 'bar', 0);
一旦我尝试推断array 的ArrayItemType,我的尝试似乎失败了。
简单地通过给定的key返回array的类型是没有问题的,如here所示。
但除此之外,我知道,我的 foo-object 中只有 Array 类型的属性,并且想要返回我通过 key 选择的数组中单个项目的类型,但这失败了,因为 typescript 在使用索引运算符访问数组时似乎忘记了它与key 属性的关系。
Typescript 4.5.4 Playground (same code as below)
/**
* I want to get the item at position 'index'
* from the properties with name 'key'
* of the structure 'Foo'
*/
function get_item<
KEY extends keyof Foo, // "zoo" | "bar"
>(foo: Foo, key: KEY, index:number)
: ArrayItemType<Foo[KEY]> // determines the type of a single element for the property 'key' beeing number|string
{
const array: Foo[KEY] = foo[key]; // this can be Array<number> or Array<string> depending on 'key'
// check if the index exists
if (index in array === false) throw new Error("Item " + index + " not found for " + key);
const item = array[index]; // at this point the type seems to have collapsed to number|string,
// discarding the fact that we know the exact type of 'array' for a given 'key'
return item; // Error
// Type 'string | number' is not assignable to type 'ArrayItemType<Foo[KEY]>'.
// Type 'string' is not assignable to type 'ArrayItemType<Foo[KEY]>'.
}
type ArrayItemType<ARRAY> = ARRAY extends Array<infer ITEM> ? ITEM : never;
/**
* Some interface with a few properties of type Array<any>
*/
interface Foo {
bar : Array<number>;
zoo : Array<string>;
}
const foo : Foo = {
bar: [0,1],
zoo: ["a", "b"],
};
// determines correct types here, this is the way i want it
const number_item :number = get_item(foo, 'bar', 1);
const string_item :string = get_item(foo, 'zoo', 1);
当然添加as ArrayItemType<Foo[KEY]> 确实可以解决问题,
但我想将这些类型转换保持在最低限度,特别是当我不明白为什么它不应该工作时(这让我想,我在某处误解了我的代码)。
那么,我错过了什么吗?
这不应该是不可能的吗?
还是KEY extends keyof Foo 的问题再次出现,允许的值比我知道的要多?
【问题讨论】:
标签: typescript typescript-typings typescript-generics