我正在尝试为以下函数进行正确的输入:
export function filter(obj: any, predicate: (value: any, key: string) => boolean) {
const result: any = {};
Object.keys(obj).forEach((name) => {
if (predicate(obj[name], name)) {
result[name] = obj[name];
}
});
return result;
}
Run Code Online (Sandbox Code Playgroud)
是否可以保留打字内容?
如果没有有关用例的更多具体信息,我倾向于这样做:
function filter<T extends object>(
obj: T,
predicate: <K extends keyof T>(value: T[K], key: K) => boolean
) {
const result: { [K in keyof T]?: T[K] } = {};
(Object.keys(obj) as Array<keyof T>).forEach((name) => {
if (predicate(obj[name], name)) {
result[name] = obj[name];
}
});
return result;
}
Run Code Online (Sandbox Code Playgroud)
我们想要filter()接受泛型类型obj的参数,这意味着您将只过滤对象类型而不是基元,并且您希望编译器跟踪实际的键值关系,而不是将其一直扩展到。因此,回调需要接受适用于 的参数;因此我们将其设为参数类型的通用回调,其中是对应的属性值类型。有关该表示法的更多信息,请参阅查找类型的文档。T extends objectTobjectpredicatevaluekeyTK extends keyof TkeyvalueT[K]keyof
对于结果,我们希望返回一个属性与 相同T但可选的对象,因为我们不知道哪些属性实际上存在。这可以表示为映射类型 { [K in keyof T]? T[K] },也称为Partial<T>。
一个问题是我必须使用类型断言来告诉编译器我期望Object.keys(obj)是Array<keyof T>( 的键的数组T)而不仅仅是string[]。这个期望可能会被违反,这就是为什么首先Object.keys()返回;string[]请参阅另一个 SO 问题以获取对此的解释。我认为在这里做出这个假设是合理的,但我将向您展示一种如果违反假设可能导致运行时错误的方法。
首先让我们测试所需的行为:
const obj = filter({ a: "hello", b: 123, c: true }, (v, k) => k === "b");
/* const obj: {
a?: string | undefined;
b?: number | undefined;
c?: boolean | undefined;
} */
console.log(obj); // {b: 123}
Run Code Online (Sandbox Code Playgroud)
看起来不错; 编译器对参数感到满意,filter()并返回带有可选属性的值。
这是糟糕的情况:
interface Foo {
x: string,
y: string,
}
interface Bar extends Foo {
z: number;
}
const bar: Bar = { x: "hello", y: "goodbye", z: 100 };
const foo: Foo = bar; // acceptable because Bar extends Foo
filter(foo, (v, k) => v === v.toLowerCase() ); // compiles fine, but
// RUNTIME TypeError: v.toLowerCase is not a function
Run Code Online (Sandbox Code Playgroud)
编译器没有意识到foo具有number-valued 属性,因为我们已经扩展bar到Foo,但predicate回调实际上依赖v于string. 编译后,您会收到运行时错误。如果您担心这种可能性,那么您可能需要更严格的类型来filter()强制predicate真正采用 type 的值(value: unknown, key: PropertyKey),但这使用起来会更烦人。这实际上取决于用例。
| 归档时间: |
|
| 查看次数: |
4259 次 |
| 最近记录: |