7

在 TypeScript 中要求模块实现接口似乎非常有用。他们选择不实施这种能力有什么特别的原因吗?

我想不出任何理由为什么不允许模块实现接口是不可取的,但如果是这样,那么有没有其他方法要求模块提供一组特定的属性/方法?

4

3 回答 3

4

如果模块不遵循这样的接口(技术上非零运行时开销,但实际上不太重要),您可以强制编译错误:

interface foo {
    bar(): number;
}

module mod {
    export function bar(): number {
        return 0;
    }
}
var mod_is_foo: foo = mod; // errors if you change 'number' to 'string' above

至于为什么不能说module mod implements foo所有功能都从负 100 开始

var编辑添加——如果你想避免创建一个新的顶级变量,你可以写一些其他(有点古怪)的东西来代替上面的语句:

<foo>mod; // Shortest, probably fastest?
<foo>undefined === mod; // Clearest non-var version?
于 2013-04-18T00:52:45.553 回答
0

Ryan 实际上是 Typescript 团队的成员,所以他的回答几乎是最终的。但我个人认为它不提供您所寻求的语法很好。

原因是模块更像是一个实例,而不是可以被实例化的东西(例如一个类)。通过这种方式,它更接近于一个 var 而不是一个类。

所以原因就变成了它类似于你写的原因:

var x:foo; 

代替

var x implements foo;

模块的行为与您可以做的相同

var y:foo = mod;

正如瑞安已经指出的那样。

还要检查一下:

interface foo {
    bar(): number;
}

module mod {
    export function bar(): number {
        return 0;
    }
}

var x: foo; 
x = mod;

// Still a bit whacky but allowed as module is a type as well as an instance
var y:mod;
y = x;
于 2013-04-18T01:26:04.780 回答
0

您可以将您的模块放在具有明确定义接口的 TypeScript 类中。一个小缺点是您需要在使用之前实例化该类。

./脚.ts

export default interface Foo {
    bar(): number;
}

./FooImpl.ts

import Foo from "./Foo";

export default class FooImpl implements Foo {
    bar(): number {
        return 13;
    }
}

./Main.ts

import Foo from "./Foo";
import FooImpl from "./FooImpl";

const foo: Foo = new FooImpl();

export default function main(): number {
    return foo.bar();
}

./FooMock.ts

import Foo from "./Foo";

export default class FooMock implements Foo {
    bar(): number {
        return 42;
    }
}

./Main.test.ts

import main from "./Main";

jest.mock('./FooImpl', () => {
    return jest.requireActual('./FooMock').default;
});

describe('Main', () => {
    it('should return 42 for the mock Foo implementation', () => {
        expect(main()).toBe(42);
    });
});
于 2021-12-18T13:08:27.723 回答