我只是想在typescript接口中声明一个静态属性?我没有找到任何关于这方面的资料。
interface myInterface {
static Name:string;
}
这可能吗?
我只是想在typescript接口中声明一个静态属性?我没有找到任何关于这方面的资料。
interface myInterface {
static Name:string;
}
这可能吗?
当前回答
这里有一个相当简单的方法:
interface MyClass {
new (): MyClassInstance;
staticMethod(): string;
}
interface MyClassInstance {
instanceMethod(): string;
}
const Class: MyClass = class {
static staticMethod() {
return "This is a static method";
}
instanceMethod() {
return "This is an instance method";
}
}
Class.staticMethod();
// Has type MyClassInstance
const instance = new Class();
instance.instanceMethod();
请注意,这并不允许您像通常那样让类扩展接口,但对于许多情况来说,这已经足够好了。
其他回答
如果您正在寻找定义一个静态类(即。所有的方法/属性都是静态的),你可以这样做:
interface MyStaticClassInterface {
foo():string;
}
var myStaticClass:MyStaticClassInterface = {
foo() {
return 'bar';
}
};
在这种情况下,静态“类”实际上只是一个普通的-ol'-js-object,它实现了MyStaticClassInterface的所有方法
我有点惊讶于上面的答案是多么的复杂!但也许这只是因为这个帖子太老了。
编辑:实际上,在经过一些测试后,我最初的尝试被证明是无用的,而且这个问题比我最初预期的要更难解决。
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的最新版本中),但静态属性将被忽略。似乎实现任何东西都只适用于原型的两个方向(到/从)。
在TypeScript中,你不能在接口上定义静态属性。
假设您想要更改Date对象,而不是尝试添加到Date的定义中,您可以包装它,或者简单地创建富Date类来完成Date没有完成的工作。
class RichDate {
public static MinValue = new Date();
}
因为Date是TypeScript中的一个接口,你不能使用extends关键字将它扩展为一个类,这有点遗憾,因为如果Date是一个类,这将是一个很好的解决方案。
如果你想扩展Date对象以在原型上提供MinValue属性,你可以:
interface Date {
MinValue: Date;
}
Date.prototype.MinValue = new Date(0);
使用:
var x = new Date();
console.log(x.MinValue);
如果你想让它在没有实例的情况下可用,你也可以…但这有点繁琐。
interface DateStatic extends Date {
MinValue: Date;
}
Date['MinValue'] = new Date(0);
使用:
var x: DateStatic = <any>Date; // We aren't using an instance
console.log(x.MinValue);
我的解决方案对于添加额外静态构造函数的用例非常有效。我已经测试过了,它通过了所有的测试。如果有人发现有问题,请告诉我。
我做了一个泛型类型,它接受接口和静态接口。
它适用于具体类和抽象类。
我使用条件类型来设计它,这样所有的错误都可以传播 到实现接口的类,而不是接口本身。
注意:错误传播允许vscode快速修复(实现所有方法)。唯一的缺点是你必须自己应用static关键字,因为没有快速修复这个错误的方法。
的接口:
type Class<T = any> = new (...args: any[]) => T;
type AbstractClass<T = any> = abstract new (...args: any[]) => T;
type Interface<C extends Class<InstanceType<C>> | AbstractClass<InstanceType<C>>, SI, I = {}> =
C extends Class<InstanceType<C>>
// ConcreteClass
? InstanceType<C> extends I
? C extends (SI & Class<InstanceType<C>>)
? (InstanceType<C> & I)
: (SI & Class<InstanceType<C>>) // Indicate StaticInterface Error
: I // Indicate Interface Error
// AbstractClass
: InstanceType<C> extends I
? C extends (SI & AbstractClass<InstanceType<C>>)
? (InstanceType<C> & I)
: (SI & AbstractClass<InstanceType<C>>) // Indicate StaticInterface Error
: I // Indicate Interface Error
用法:
interface MyInterface {
instanceMethod(): number;
}
interface MyStaticInterface {
staticMethod(): number;
}
class MyClass implements Interface<typeof MyClass, MyStaticInterface, MyInterface> {
static staticMethod(): number {
return 50;
}
instanceMethod(): number {
return 100;
}
static otherStatic() {
return "HELLO"
}
otherInstance() {
return "GOODBYE"
}
}
abstract class MyClass1 implements Interface<typeof MyClass1, MyStaticInterface, MyInterface> {
static staticMethod(): number {
return 50;
}
instanceMethod(): number {
return 20;
}
static otherStatic() {
return "HELLO"
}
otherInstance() {
return "GOODBYE"
}
abstract abstractMethod() : number;
}
虽然静态关键字不支持接口在Typescript 但我们可以通过创建一个具有静态成员的函数接口来实现。
在下面的代码中,我创建了一个函数接口Factory,它有两个静态成员serialNumber和printSerial。
// factory is a function interface
interface Factory<T> {
(name: string, age: number): T;
//staic property
serialNumber: number;
//static method
printSrial: () => void;
}
class Dog {
constructor(public name: string, public age: number) { }
}
const dogFactory: Factory<Dog> = (name, age) => {
return new Dog(name, age);
}
// initialising static members
dogFactory.serialNumber = 1234;
dogFactory.printSrial = () => console.log(dogFactory.serialNumber);
//instance of Dog that DogFactory creates
const myDog = dogFactory("spike", 3);
//static property that returns 1234
console.log(dogFactory.serialNumber)
//static method that prints the serial 1234
dogFactory.printSrial();