typescript - 如何在 Typescript 中使用函数增强接口?
问题描述
我有一个看起来像这样的界面:
export interface Attribute {
name: string;
}
有了这个,我可以使用这个语法来创建一个Attribute
:
const attr: Attribute = {
name: "foo"
};
我的问题是我不想使用类,因为它们笨拙且不够灵活,但我想继续使用上面的语法来创建对象,因为它非常简洁。我读过可以进行声明合并,所以我尝试这样做以向该接口添加一个新函数:
import { Attribute } from "./Attribute";
declare module "./Attribute" {
interface Attribute {
matches(other: Attribute): boolean;
}
}
Attribute.prototype.matches = function (other: Attribute): boolean {
return this.name === other.name;
};
这里的问题是prototype
由于接口在运行时不可用,因此无法增加。如果我将Attribute
接口与一个类合并:
export class Attribute {}
export interface Attribute {
name: string;
}
有一个原型并且增强编译但我仍然不能使用它:
import { Attribute } from "./Attribute";
import "./AttributeAugments";
const attr: Attribute = {
name: "foo"
};
// ^^^--- Property 'matches' is missing in type '{ id: number; name: string; }' but required in type 'Attribute'
console.log(attr);
有没有办法以某种方式做到这一点?我的目标是能够做attr.matches(other)
而不是不得不做matches(attr, other)
。这样我就可以像做函数链接attr.a().b().c()
而不是必须做c(b(a(attr)))
.
解决方案
从您的代码来看,Attribute
是一个接口。一个类型或接口在 JavaScript 中编译为空;因此,你不能在你的问题中这样做。
declare module "./Attribute" {
interface Attribute {
matches(other: Attribute): boolean;
}
}
// No such "Attribute" variable!
Attribute.prototype.matches = function (other: Attribute): boolean {
return this.name === other.name;
};
const attr: Attribute = {
name: "foo"
};
attr.matches(); // error, attr's prototype is Object, not Attribute
// because there is no constructor function or class Attribute
有一些方法可以解决您的问题。
matches
(1)每次创建类型变量时始终包含方法Attribute
:
export function matches(this: Attribute, other: Attribute): boolean {
return this.name === other.name;
};
const attr: Attribute = {
name: "foo",
matches,
}; // works
(2) 使用Attribute
类但简化其实例化:
type ExcludeMethods<T extends object> = Pick<
T,
{
[x in keyof T]: T[x] extends Function ? never : x;
}[keyof T]
>; // without this type, "matches" method is required in the object literal!
class Attribute {
constructor(init: ExcludeMethods<Attribute>) {
Object.assign(this, init);
}
name: string;
matches(other: Attribute): boolean {
return this.name === other.name;
}
}
const attr = new Attribute({ name: "foo" }); // works
const attr2 = new Attribute({}); // error, name is required
如果name: string
属性导致编译错误,请添加非空断言(使其变为name!: string
),因为我们非常确定非函数字段必须存在于Object.assign
to 中this
。
推荐阅读
- apache-flink - Flink - 纱线节点终止后无法恢复
- python - add_axes 涵盖以前的情节
- python - 为什么 heapq.heapify 在将切片传递给列表时不会更改列表?
- push-notification - Expo如何管理一千个推送通知的FCM令牌?
- jquery - 单击事件时未更新数据 ID
- git - 通过 Git 在 Github 的公共存储库中上传时卡住了
- python - 如何在python中使用单个数据点创建多个散点图?
- reflection - 如何在不实际对路径进行硬编码的情况下确定记录中字段的 json 路径?
- c - 为什么lua luaZ_fill 会这样读取数据
- javascript - AWS IOT GetThingShadow API 请求发送响应“签名过期”