TypeScript接口函数属性: 有什么区别?

31

请问为什么在这段代码中,对InterfaceA类型常量的赋值是有效的,但对InterfaceB类型常量的赋值会抛出错误:

interface InterfaceA {
  doSomething (data: object): boolean;
}

interface InterfaceB {
  doSomething: (data: object) => boolean;
}

function doIt (data: { type: string; }): boolean {
    return true;
}

const A: InterfaceA = {
    doSomething: doIt
};
const B: InterfaceB = {
    doSomething: doIt
};

在线演示请查看: http://www.typescriptlang.org/play/index.html?ssl=19&ssc=1&pln=1&pc=1#code/JYOwLgpgTgZghgYwgAgJLmvJBBZBvAWAChlkATAewGUKBbCMAC1AHNkAKMuMOALmQoAjAFYQEYAJT9BFCgBsIcEAG5iAX2LFQkWIhTodWCACF8xUpRr0mrfp258BIsZOQBeAHzIZ8xSvWaRDAAriDiwBQg5BSoYBxcPPx4yGAAngAOEPwAzmBQrMrIalLesgpKZkQAkFAMwVBRecEQqkQaRMQIkbnI2PwGmHq4bpVVlnQMzCAs-JSx6q1dID3G-Ri6SKYjhNXj1lMz0fNtrUA

在我看来,这两个接口定义的是相同的内容,只是符号表示不同。

如果这不是 TypeScript 中的一个 bug 并且有真正的理由,那么我们来看我的第二个问题: 我需要指定 "doSomething" 是可选的,并且可以是函数或 RegExp:

interface InterfaceB {
  doSomething?: ((data: object) => boolean) | RegExp;
}`

我该如何使用InterfaceA的符号表示来实现这个?


你看过这个帖子吗?https://dev59.com/6VMI5IYBdhLWcg3wg7qp - Dai
1
我不认为这个线程回答了我的问题。它涉及类中不同的方法定义。不同的符号生成不同的代码 - 而在查看生成的代码时,一切都是透明和清晰的。我的问题涉及接口,这里你无法查看生成的代码,因为它们不会生成代码。 - user4449804
1个回答

48

1.) 方法和函数属性声明之间存在差异:

interface InterfaceA {
  doSomething(data: object): boolean; // method declaration
}

interface InterfaceB {
  doSomething: (data: object) => boolean; // function as property declaration
}

2.) TypeScript 2.6引入了一个编译器标志,用于更强类型、sound函数类型:
--strictFunctionTypes下,函数类型参数位置被检查contravariantly instead of bivariantly。这种更严格的检查适用于所有函数类型除了那些起源于方法或构造函数声明的函数类型。(我的强调) 因此,总的来说这是一件好事。在你的例子中,InterfaceB有以下协定:“每个能够处理一般object的函数都是兼容的”。但是你想分配一个函数doIt,它期望特定类型的对象{ type: string; }作为输入。使用InterfaceB的客户端认为传递object就足够了,但实现doIt需要更具体的内容,所以你正确地得到了错误提示。

为什么InterfaceA没有出现错误?

相比之下,像InterfaceA中的方法,由于实际原因,被--strictFunctionTypes排除在外。开发人员决定在内置的Array等方法中,类型系统不要太过严格,以在正确性和生产力之间保持合理的平衡。
所以,为了更强的类型,我更喜欢以下类型,适用于您的情况(样例):
interface InterfaceB {
  doSomething: ((data: { type: string; }) => boolean) | RegExp;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接