TypeScript 类与同名接口之间的关系

Posted

技术标签:

【中文标题】TypeScript 类与同名接口之间的关系【英文标题】:Relationship between a TypeScript class and an interface with the same name 【发布时间】:2017-08-20 16:59:46 【问题描述】:

对于 TypeScript 类和同名接口之间看似特殊的关系,我很难找到任何清晰的文档或解释。

接口与类同名有什么意义? 为什么与接口共享名称的类会自动实现该接口? 为什么当类和接口具有相同名称时,编译器会抱怨我的只读接口字段的 getter 实现,但如果名称不同则接受实现? 是否有解决这些问题的规范文档?

代码:

// Co-named interface and class doesn't like readonly property implementation:

interface Foo 
  readonly x: number; // Error: Duplicate identifier 'x'
  y: number;


class Foo 
  get x(): number  // Error: Duplicate identifier 'x'
    return 0;
  

  y = 1;


// Same as above, but different class name + explicit `implements`

class Bar implements Foo 
  get x(): number  // No error!
    return 0;
  

  y = 1;


// Duplicating the first example, but explicitly implementing the co-named interface:

interface Baz 
  readonly x: number; // Error: Duplicate identifier 'x'
  y: number;


class Baz implements Baz 
  get x(): number  // Error: Duplicate identifier 'x'
    return 0;
  

  y = 1;

【问题讨论】:

【参考方案1】:

这是特定于访问者的限制,到目前为止,Typescript 团队在此问题上出现了unwilling to comment。

class Foo 
  readonly x: number = 0;


class Bar extends Foo 
interface Bar 
  readonly x: 2;


const bar = new Bar();
bar.x; // type is 2, no error

团队commented 认为“[w] 属性是作为字段实现还是作为 getter/setter 对实现是实现细节,而不是类型的一部分”,但这是显然不是 Typescript 4.2 的情况:

class Baz extends Foo 
    // error: "'x' is defined as a property in class 'Foo',
    //         but is overridden here in 'Baz' as an accessor."
    get x() 
        return 2;
    

我无法解释团队的反应。 getter/setter 不属于类型系统的评论来自 2015 年,可能已经过时了。

【讨论】:

TS4.3 beta 现在允许您向接口添加 getter 和 setter。也许这现在揭示了它们在内部的表现方式是多么不同。【参考方案2】:

模块will be merged内的同名接口:

interface Foo 
    x: number;


interface Foo 
    y: string;


let g =  as Foo;
g.x; // OK
g.y; // OK

类声明创建both a constructor function as well as type declaration,这实质上意味着所有类都可以用作接口。

class Bar 
    y: number;


interface IBaz extends Bar   // includes y: number

class CBaz implements Bar 
    y: number = 5;

因此,一个类和一个接口同名就相当于两个接口同名,如果接口的两个实例都重新声明了不同类型的相同成员,就会产生合并冲突。

奇怪的是,Typescript 允许这样做:

export interface Foo 
    readonly x: number;


export class Foo 
    readonly x: number = 3;

但它不允许get x() return 3; ,即使它们都生成为readonly x: number,所以我只能想象类型检查器在合并期间认为它们是不同的,即使它们在语义上是相同的(这就是为什么你可以扩展接口并将只读属性指定为getter函数)。

【讨论】:

谢谢。发布了一个问题,以澄清编译器为何以这种方式抱怨:github.com/Microsoft/TypeScript/issues/14882 @NathanRidley 您收到的对您的问题的“回复”很不幸,并且没有很好地反映打字稿团队。

以上是关于TypeScript 类与同名接口之间的关系的主要内容,如果未能解决你的问题,请参考以下文章

类之间的关系

类与接口的关系

java--类与类之间的关系

TypeScript开发实战

类与类之间的几种关系

类与类之间的关系