我们有以下TypeScript代码:
type Option = {
name: string;
};
export const filterOptions = <T extends string>(
options: Record<T, Option>,
): unknown[] =>
Object.entries(options)
.map(([key, entry]) => ({
key,
...entry, // <--- Error: Spread types may only be created from object types.
}))
.filter(() => {
// do filtering stuff...
});预期的entry类型是Option,但TS不承认这一点,并假设它是unknown。问题似乎是泛型类型T,因为将options类型更改为Record<string, Option>将entry类型更改为Option (如预期的那样)。
这是一个TS游乐场连接
我们搞错什么了?为什么这种类型没有得到正确的识别?
发布于 2021-11-30 10:04:42
我刚刚检查了Object.entries()的输入:
/**
* Returns an array of key/values of the enumerable properties of an object
* @param o Object that contains the properties and methods. This can be an object that you created or an existing Document Object Model (DOM) object.
*/
entries<T>(o: { [s: string]: T } | ArrayLike<T>): [string, T][];备选案文1
似乎,您可以显式地将值参数类型传递给Object.entries()。这样,它就可以对typings进行正则化。
const filterOptions = <T extends string>(
options: Record<T, Option>,
) => {
return Object.entries<Option>(options) // added option type here!
.map(([key, entry]) => ({
key,
...entry, // It knows for sure now..
}))
.filter(() => {
// do filtering stuff...
});
}选项2
Record类型使用symbols / numbers和strings作为键。
/**
* Construct a type with a set of properties K of type T
*/
type Record<K extends keyof any, T> = {
[P in K]: T;
};例如,这确实有效:
const d = Symbol('somedescripton')
const a: Record<string, Option> = {
'a': {name: 'strrst'},
b: {name:'sdfsdf'},
0: {name: 'srfsdfds'},
d: {name: 'sdfsdfd'}
}Object.entries()将将其转换为string键,但它仍然接受,Symbols和numbers也是如此!^因此,对于只有string键的Record类型,您需要自己键入才能省略显式强制转换:
type StringRecord<T extends string, K> = {[key in keyof T]: K }
const filterOptions = <T extends string>(
options: StringRecord<T, Option>,
) => {
return Object.entries(options)
.map(([key, entry]) => ({
key,
...entry, // works now..
}))
.filter(() => {
// do filtering stuff...
});
}https://stackoverflow.com/questions/70166541
复制相似问题