我正在用TypeScript编写一个API Package 器库,我希望TypeScript能够根据API调用的用户输入给予精确的返回类型信息。我还想将API响应转换为对库使用者更有用的东西。
假设我有一个返回类型为someType
的API端点:
type someType = {
statuses?: string[], //
distances?: number[] // all arrays will be of equal length
}
其中数组总是具有相同的长度并且对应于给定索引处的相同特征。所以我想把响应转换成someOtherType
类型的数组:
type someOtherType = {
status?: string,
distance?: number
}
用户可以根据someType
键数组控制响应someType
上的属性。所以我想让TypeScript知道哪些属性会在返回的对象上,哪些不会。我尝试了以下方法,但没有效果:
type someTypeKeys = keyof someType
type someMappedTypeKeys = keyof someOtherType
const Mapping: Record<someTypeKeys, someMappedTypeKeys> = {
statuses: "status",
distances: "distance"
}
const someObj: someType = {
statuses: ["1"],
}
type WithRequired<T, K extends keyof T> = T & Required<Pick<T, K>>
type FunctionReturnType<T extends keyof someType> = Required<Pick<someOtherType, typeof Mapping[T]>>
function a<T extends (keyof someType)[]>(arg: T): Required<Pick<someOtherType, typeof Mapping[typeof arg[number]]>>[] {
const someResponseObj = { // some imaginary response
statuses: ["1"],
} as unknown as Required<Pick<someType, typeof arg[number]>>
const arr: Required<Pick<someOtherType, typeof Mapping[typeof arg[number]]>>[] = []
for (let i = 0; i < (someObj.statuses.length) && i ; ++i) {
const mappedObj = arg.reduce((agg, key) => {
const mappedKey = Mapping[key]
const currArr = someObj[key]
if (currArr === undefined) {
return agg
} else {
return {...agg, [mappedKey]: currArr[i]}
}
}, {}) as Required<Pick<someOtherType, typeof Mapping[typeof arg[number]]>>
arr.push(mappedObj)
}
return arr;
}
const b = a(["statuses"])
b[0].distance // should be undefined
b // can I make TS be able to tell the properties available on objects in array b?
2条答案
按热度按时间soat7uwm1#
给定输入类型
以及Map类型
我们想将
a
的呼叫签名表示为其中
OutputType<K>
表示给定K[]
类型的keys
集合的输出数组的元素类型。我们将使用一些helper类型来构建它:
MapKeys<T, M>
使用键重Map将T
的键更改为MapM
中的键,而不更改值。PropElements<T>
将对象的属性值-with-array-property-values更改为只保存元素类型的对象。那么
OutputType<K>
就是:我们从
K
中选取SomeType
的键,用PropElements
获取它们的数组元素类型,然后用MapKeys
和Mapping
Map键。不幸的是,这将最终显示为智能感知。为了让它看起来像一个普通的对象类型,我们将使用How can I see the full expanded contract of a Typescript type?中的技巧:让我们测试一下:
并确保它在调用
a()
时如所宣传的那样工作:这是打字。至于实现,这可能取决于您的用例;以下是一种可能方法:
它只是找出输出的数组长度,然后遍历输入对象的属性,并复制和Map键。我更关心的是调用签名类型,而不是实现中的正确性和类型验证,因此您应该确保进行了满足您需要的任何更改。
不过,为了完整性,下面是下面的内容:
看起来不错!
Playground链接到代码
bnl4lu3b2#
https://tsplay.dev/NB8lgW