我只是想在typescript接口中声明一个静态属性?我没有找到任何关于这方面的资料。
interface myInterface {
static Name:string;
}
这可能吗?
我只是想在typescript接口中声明一个静态属性?我没有找到任何关于这方面的资料。
interface myInterface {
static Name:string;
}
这可能吗?
当前回答
静态修饰符不能出现在类型成员上(TypeScript错误TS1070)。这就是为什么我建议使用抽象类和继承来解决任务:
例子
// Interface definition
abstract class MyInterface {
static MyName: string;
abstract getText(): string;
}
// Interface implementation
class MyClass extends MyInterface {
static MyName = 'TestName';
getText(): string {
return `This is my name static name "${MyClass.MyName}".`;
}
}
// Test run
const test: MyInterface = new MyClass();
console.log(test.getText());
其他回答
@duncan上面的解决方案为静态类型指定new()也适用于接口:
interface MyType {
instanceMethod();
}
interface MyTypeStatic {
new():MyType;
staticMethod();
}
静态属性通常放在对象的(全局)构造函数上,而“interface”关键字适用于对象的实例。
如果你用TypeScript编写类,前面给出的答案当然是正确的。如果你描述的是一个已经在其他地方实现的对象,那么包含静态属性的全局构造函数可以这样声明:
declare var myInterface : {
new(): Interface;
Name:string;
}
我有点惊讶于上面的答案是多么的复杂!但也许这只是因为这个帖子太老了。
编辑:实际上,在经过一些测试后,我最初的尝试被证明是无用的,而且这个问题比我最初预期的要更难解决。
After about an hour or so of tinkering however, I think I may have just found the best/cleanest solution so far (building upon my initial idea)! If the question posed is "How do I include static properties in an interface?", then I think this is a fairly decent answer. This is at least better than extending a class if all you need is an interface (compiletime typing/requirements/restraints). There's no real drawback (well, maybe one small one) to this either since the solution is 100% ambient (unlike extends-based class extension like some answers are suggesting) and classes are constants regardless (immutable references that are not hoisted when using the standard class declaration syntax instead of a class expression as I'm doing here). This incurs no runtime overhead and doesn't require runtime class inheritance. You can define the entire class (both static and non-static members) all in one (ambient class used as an) interface!
以下是如何做到这一点!
/** ./interface.ts */
// In a file module (best), or wrap in ts module or namespace block
// Putting this in a module provides encapsulation ensuring that no one is
// at risk of misusing this class (it must be used as a type only).
// Export only a type reference which will make it error is someone tries
// to use it as a value (such as in an `extends` clause, or trying to
// instantiate it).
/**
* Other Ideas For Names To Differentiate From Actual Classes/Non-Ambient Values:
* MyClassInterface or _Interface_MyClass or MyClass_Interface or Interface_MyClass
**/
declare class _MyClassInterface {
static staticProp: string;
static staticMethod(): number;
readonly prop: boolean
/**
* Note: Above, readonly won't need to be specified in the real class
* but the prop *will* still be readonly anyway.
*
* Now for the only caveat!
* It does appear however that you cannot mark anything private or
* protected in this pseudo-interface which is a bummer, only props
* and methods that appear only in the real class can be.
*/
prop2: boolean;
method(): Function;
constructor(p1: string, p2: number);
}
export type MyClassInterface = typeof _MyClassInterface;
现在使用接口
/** ./consumer.ts */
import { MyClassInterface } from "./interface" // type import
const MyClass: MyClassInterface = class {
static staticProp: string;
prop: boolean;
prop2: boolean;
protected onlyOnRealClass: boolean; /* this is ok since this prop doesn't exist on the interface */
static staticMethod() {
return 5;
}
method() {
return () => {};
}
constructor(p1: string, p2: number) {}
};
注意,typeof关键字在这里是绝对必要的(如果我没记错的话,这是因为如果没有它,typescript会认为我们在指定实例类型,而我们真正想要的是类本身的类型)。比如当我们这样做的时候
const a: MyClass = new MyClass()
没有typeof关键字,我们说a应该是MyClass的一个实例,而不是MyClass本身。
抽象确保你不会意外地尝试实例化类…
Edit: Actually I'm removing the abstract keyword from my answer because it turns out that the real class actually inherits the property of being abstract from the ambient class (makes sense), and will therefore not instantiate w/o the compiler complaining if the ambient class that provides its type is marked abstract... just gonna have to deal with ts not erroring if the ambient class is ever accidentally instantiated. It might be a decent idea then to prefix the ambient class declaration/name with an underscore and/or include the word Interface in the name so its proper use is clear (edit: I have since tackled this issue by encapsulating the interface in a file module thereby rendering it private to all other code and then exporting only a type reference to it).
这就是它的全部!
将接口放入模块中并不是完全必要的,但它提供了一些小好处,包括:
在整个实现代码中使用的“公开的”广泛使用的类型注释变得稍微小了一些,因为它不再包含关键字typeof 与包装的环境类/接口声明不同,导出/向外标识符严格来说是一种类型(别名),因此如果有人试图实例化它或在extends子句中使用它(或在其他需要运行时值的地方使用它),就会发生错误。
I'm not supplying a class name for the Class Expression in this example because Class Expressions, like all Function Expressions, will just inherit the identifier that they are assigned to if a class name if not provided. So if your identifier is identical to the name you want for that class or function anyways, you can just leave it off. Or, you may provide one inline as usual and it will take precedence over the identifier. A class or function name can also be changed after function/class creation, but only via Object.defineProperty or Object.defineProperties.
FWIW类实际上可以由另一个类实现(至少在TS的最新版本中),但静态属性将被忽略。似乎实现任何东西都只适用于原型的两个方向(到/从)。
如果您正在寻找定义一个静态类(即。所有的方法/属性都是静态的),你可以这样做:
interface MyStaticClassInterface {
foo():string;
}
var myStaticClass:MyStaticClassInterface = {
foo() {
return 'bar';
}
};
在这种情况下,静态“类”实际上只是一个普通的-ol'-js-object,它实现了MyStaticClassInterface的所有方法
你可以正常定义接口:
interface MyInterface {
Name:string;
}
但你不能这么做
class MyClass implements MyInterface {
static Name:string; // typescript won't care about this field
Name:string; // and demand this one instead
}
为了表示一个类应该遵循这个接口来获取它的静态属性,你需要一点技巧:
var MyClass: MyInterface;
MyClass = class {
static Name:string; // if the class doesn't have that field it won't compile
}
你甚至可以保留类名,TypeScript(2.0)不会介意:
var MyClass: MyInterface;
MyClass = class MyClass {
static Name:string; // if the class doesn't have that field it won't compile
}
如果你想静态地继承许多接口,你必须首先将它们合并到一个新的接口中:
interface NameInterface {
Name:string;
}
interface AddressInterface {
Address:string;
}
interface NameAndAddressInterface extends NameInterface, AddressInterface { }
var MyClass: NameAndAddressInterface;
MyClass = class MyClass {
static Name:string; // if the class doesn't have that static field code won't compile
static Address:string; // if the class doesn't have that static field code won't compile
}
或者如果你不想命名合并接口,你可以这样做:
interface NameInterface {
Name:string;
}
interface AddressInterface {
Address:string;
}
var MyClass: NameInterface & AddressInterface;
MyClass = class MyClass {
static Name:string; // if the class doesn't have that static field code won't compile
static Address:string; // if the class doesn't have that static field code won't compile
}
工作示例