Я просто хочу объявить статическое свойство в интерфейсе машинописного текста ? Я нигде не нашел по этому поводу.
interface myInterface {
static Name:string;
}
Является ли это возможным?
Я просто хочу объявить статическое свойство в интерфейсе машинописного текста ? Я нигде не нашел по этому поводу.
interface myInterface {
static Name:string;
}
Является ли это возможным?
Ответы:
Вы не можете определить статическое свойство интерфейса в TypeScript.
Допустим, вы хотите изменить 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);
extendsключевого слова. Вы просто не можете расширить интерфейс классом (что вам нужно сделать, чтобы добавить статическое свойство).
Следуйте ответу @Duncan @ Bartvds здесь, чтобы предоставить работоспособный способ по прошествии лет.
На данный момент после выпуска Typescript 1.5 (@ 15 июня 2015 г.) ваш полезный интерфейс
interface MyType {
instanceMethod();
}
interface MyTypeStatic {
new():MyType;
staticMethod();
}
может быть реализовано таким образом с помощью декоратора.
/* class decorator */
function staticImplements<T>() {
return <U extends T>(constructor: U) => {constructor};
}
@staticImplements<MyTypeStatic>() /* this statement implements both normal interface & static interface */
class MyTypeClass { /* implements MyType { */ /* so this become optional not required */
public static staticMethod() {}
instanceMethod() {}
}
См. Мой комментарий в github open issue 13462 .
Визуальный результат: Ошибка компиляции с отсутствующим намеком на статический метод.

После реализации статического метода подсказка для метода отсутствует.

Компиляция прошла после того, как статический интерфейс и нормальный интерфейс были выполнены.

Вы можете определить интерфейс как обычно:
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
}
Рабочий пример
@staticImplements.
reply(msg: IBotMsg): Promise<IBotReply>
Статические свойства обычно помещаются в (глобальный) конструктор объекта, тогда как ключевое слово «interface» применяется к экземплярам объекта.
Предыдущий ответ, конечно, правильный, если вы пишете класс на TypeScript. Это может помочь другим узнать, что если вы описываете объект, который уже реализован где-то еще, то глобальный конструктор, включающий статические свойства, может быть объявлен следующим образом:
declare var myInterface : {
new(): Interface;
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();
}
implement?
MyType(как в class Foo implements MyType). Статический интерфейс действительно полезен только в определениях, при описании существующего кода JS.
Если вы хотите определить статический класс (т.е. все методы / свойства статичны), вы можете сделать что-то вроде этого:
interface MyStaticClassInterface {
foo():string;
}
var myStaticClass:MyStaticClassInterface = {
foo() {
return 'bar';
}
};
В этом случае статический «класс» на самом деле просто простой-ол'-js-объект, который реализует все методы MyStaticClassInterface
Да, это возможно. Вот решение
export interface Foo {
test(): void;
}
export namespace Foo {
export function statMethod(): void {
console.log(2);
}
}
Fooвместо определения класса? где Class Foo будет реализовывать statMethod (), это кажется чем-то вроде взлома, особенно, поскольку пространства имен сейчас вроде как устарели ...
waiting more feedback. Итак, вы либо ждете, пока статические методы не будут добавлены в интерфейс, либо сделаете это так.
export namespaceсамом деле ваша реализация класса? Кажется, это действительно сильно меняет ситуацию. Интересно, что еще ломается в классах?
Другой вариант, не упомянутый здесь, - это определение переменной с типом, представляющим статический интерфейс, и присвоение ему выражения класса:
interface MyType {
instanceMethod(): void;
}
interface MyTypeStatic {
new(): MyType;
staticMethod(): void;
}
// ok
const MyTypeClass: MyTypeStatic = class MyTypeClass {
public static staticMethod() { }
instanceMethod() { }
}
// error: 'instanceMethod' is missing
const MyTypeClass1: MyTypeStatic = class MyTypeClass {
public static staticMethod() { }
}
// error: 'staticMethod' is missing
const MyTypeClass2: MyTypeStatic = class MyTypeClass {
instanceMethod() { }
}
Эффект такой же, как в ответе с декораторами , но без накладных расходов декораторов.
Соответствующее предложение / обсуждение на GitHub
Вы можете объединить интерфейс с пространством имен, используя то же имя:
interface myInterface { }
namespace myInterface {
Name:string;
}
Но этот интерфейс полезен только для того, чтобы знать, что у него есть свойство Name. Вы не можете это реализовать.
Я нашел способ сделать это (без декораторов) для моего конкретного случая использования.
Важной частью проверки статических членов является IObjectClassиспользование cls: IObjectClass<T>в createObjectметоде:
//------------------------
// Library
//------------------------
interface IObject {
id: number;
}
interface IObjectClass<T> {
new(): T;
table_name: string;
}
function createObject<T extends IObject>(cls: IObjectClass<T>, data:Partial<T>):T {
let obj:T = (<any>Object).assign({},
data,
{
id: 1,
table_name: cls.table_name,
}
)
return obj;
}
//------------------------
// Implementation
//------------------------
export class User implements IObject {
static table_name: string = 'user';
id: number;
name: string;
}
//------------------------
// Application
//------------------------
let user = createObject(User, {name: 'Jimmy'});
console.log(user.name);
Хотя ключевое слово static не поддерживается в интерфейсе в Typescript, мы можем добиться этого, создав класс, function interfaceкоторый имеет статический член.
В моем следующем коде я создал интерфейс функции, 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();
Я применил решение, подобное Камилу Сзоту , и оно дает нежелательный эффект. У меня недостаточно репутации, чтобы опубликовать это в качестве комментария, поэтому я размещаю его здесь на случай, если кто-то попробует это решение и прочитает это.
Решение такое:
interface MyInterface {
Name: string;
}
const MyClass = class {
static Name: string;
};
Однако использование выражения класса не позволяет мне использовать его MyClassкак тип. Если я напишу что-то вроде:
const myInstance: MyClass;
myInstanceоказывается типа any, и мой редактор показывает следующую ошибку:
'MyClass' refers to a value, but is being used as a type here. Did you mean 'typeof MyClass'?ts(2749)
В итоге я теряю более важную типизацию, чем та, которую я хотел достичь с помощью интерфейса для статической части класса.
Решение Вэла с использованием декоратора позволяет избежать этой ловушки.