我完全不同意 Typescript 团队的决定...
按照他们的逻辑,Object.values 应该总是返回 any,因为我们可以在运行时添加更多属性...
我认为正确的做法是创建具有可选属性的接口,并在您进行时设置(或不设置)这些属性...
所以我只是简单地在本地覆盖了ObjectConstructor 接口,方法是在我的项目中添加一个声明文件(又名:whatever.d.ts),其中包含以下内容:
declare interface ObjectConstructor extends Omit<ObjectConstructor, 'keys' | 'entries'> {
/**
* Returns the names of the enumerable string properties and methods of an object.
* @param obj Object that contains the properties and methods. This can be an object that you created or an existing Document Object Model (DOM) object.
*/
keys<O extends any[]>(obj: O): Array<keyof O>;
keys<O extends Record<Readonly<string>, any>>(obj: O): Array<keyof O>;
keys(obj: object): string[];
/**
* Returns an array of key/values of the enumerable properties of an object
* @param obj 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 extends { [K: Readonly<string>]: any }>(obj: T): Array<[keyof T, T[keyof T]]>
entries<T extends object>(obj: { [s: string]: T } | ArrayLike<T>): [string, T[keyof T]][];
entries<T>(obj: { [s: string]: T } | ArrayLike<T>): [string, T][];
entries(obj: {}): [string, any][];
}
declare var Object: ObjectConstructor;
注意:
原始类型(对象)的Object.keys/Object.entries 将返回never[] 和[never, never][] 而不是正常的string[] 和[string, any][]。如果有人知道解决方案,请随时在 cmets 中告诉我,我将编辑我的答案
const a: {} = {};
const b: object = {};
const c: {x:string, y:number} = { x: '', y: 2 };
// before
Object.keys(a) // string[]
Object.keys(b) // string[]
Object.keys(c) // string[]
Object.entries(a) // [string, unknown][]
Object.entries(b) // [string, any][]
Object.entries(c) // [string, string|number][]
// after
Object.keys(a) // never[]
Object.keys(b) // never[]
Object.keys(c) // ('x'|'y')[]
Object.entries(a) // [never, never][]
Object.entries(b) // [never, never][]
Object.entries(c) // ['x'|'y', string|number][]
所以,谨慎使用...