TypeScript 정적 클래스


145

C #과 같은 구문을 좋아하기 때문에 기존 JS에서 TypeScript로 이동하고 싶었습니다. 내 문제는 TypeScript에서 정적 클래스를 선언하는 방법을 찾을 수 없다는 것입니다.

C #에서는 종종 정적 클래스를 사용하여 변수와 메서드를 구성하여 개체를 인스턴스화하지 않고도 명명 된 클래스로 묶습니다. 바닐라 JS에서는 간단한 JS 객체 로이 작업을 수행했습니다.

var myStaticClass = {
    property: 10,
    method: function(){}
}

TypeScript에서는 C-sharpy 접근법을 사용하려고하지만 TS에는 정적 클래스가 존재하지 않는 것 같습니다. 이 문제에 대한 적절한 해결책은 무엇입니까?

답변:


166

TypeScript는 C #이 아니므로 TypeScript에서 동일한 C # 개념을 기대할 필요는 없습니다. 문제는 왜 정적 클래스를 원합니까?

C #에서 정적 클래스는 단순히 서브 클래 싱 할 수없는 클래스이며 정적 메서드 만 포함해야합니다. C #에서는 클래스 외부에서 함수를 정의 할 수 없습니다. 그러나 TypeScript에서는 이것이 가능합니다.

함수 / 메소드를 네임 스페이스 (예 : 전역이 아닌)에 넣는 방법을 찾고 있다면, 예를 들어 TypeScript의 모듈 사용을 고려할 수 있습니다.

module M {
    var s = "hello";
    export function f() {
        return s;
    }
}

따라서 외부에서는 Mf ()에 액세스 할 수 있지만 s는 액세스 할 수 없으며 모듈을 확장 할 수 없습니다.

자세한 내용은 TypeScript 사양 을 참조하십시오.


그래서 모듈은 정적 메소드를 가질 수 있지만 클래스는 할 수 없습니까? 그러나 모듈은 정적 데이터를 가질 수 없습니다. 아무것도 인스턴스화하지 않고 데이터와 코드를 래핑하는 데 JS만큼 편리하지 않습니다.
dcsan

당신이 포함해야한다는 점을 포함하는 유용 할 수 있습니다 .js당신에 html. 그래서 위해 Angular 2당신은 아마 사용하고 System... 할 so'd System.import("Folder/M");(또는 경로는 컴파일에 무엇이든 .js파일)을 전bootstrap import
Serj 세이건

11
더 이상 사용되지 않습니다. 또한 tslint는 더 이상 모듈과 네임 스페이스에 대해 그렇게 할 수 없습니다. 여기에 읽기 : palantir.github.io/tslint/rules/no-namespace
플로리안 레이 쳅

정적 클래스를 사용하는 유스 케이스가 있습니다. 현재 정적 메소드 만 포함하는 클래스가 있습니다. 프로젝트에서 인스턴스화 할 수있는 각 클래스에 대해 일종의 구성을 제공해야합니다. 이러한 클래스를 정적으로 선언하면 인스턴스화되지 않을뿐만 아니라 다른 개발자가 인스턴스 멤버를 추가하는 것을 피할 수 있습니다.
mdarefull

@florian leitgeb 정적 메소드 및 / 또는 추상 키워드 만있는 클래스가 선호되는 방법은 무엇입니까? 그것은 더 이상 사용되지 않는 것으로 보이는 모듈과 비교할 때
엉망인

182

추상 클래스는 TypeScript 1.6부터 TypeScript의 일류 시민이었습니다. 추상 클래스를 인스턴스화 할 수 없습니다.

예를 들면 다음과 같습니다.

export abstract class MyClass {         
    public static myProp = "Hello";

    public static doSomething(): string {
      return "World";
    }
}

const okay = MyClass.doSomething();

//const errors = new MyClass(); // Error

6
정적 클래스를 다룰 때 이것이 가장 좋은 반응이며 이것을 찬성합니다. Singleton동일한 클래스 인스턴스의 공유 메모리 패턴을위한 것입니다. 또한 정적 클래스에는 정의에 따라 인스턴스가 없으므로 클라이언트가 초기화하려고하면 예외를 발생시켜야합니다.
loretoparisi

1
우리는 추상 수업을 만들 수 있습니까?
KimchiMan

@KimchiMan-예, abstract키워드는 TypeScript에서 지원됩니다.
Fenton

1
사용하도록 업데이트되었습니다 abstract! @ KimchiMan-좋은 생각!
흑요석

3
생성자를 비공개로 표시하는 것보다이 방법이 더 나은 방법입니까?
Joro Tenev

72

클래스의 정적 속성 및 메서드 정의는 Typescript Language Specification의 8.2.1에 설명되어 있습니다 .

class Point { 
  constructor(public x: number, public y: number) { } 
  public distance(p: Point) { 
    var dx = this.x - p.x; 
    var dy = this.y - p.y; 
    return Math.sqrt(dx * dx + dy * dy); 
  } 
  static origin = new Point(0, 0); 
  static distance(p1: Point, p2: Point) { 
    return p1.distance(p2); 
  } 
}

어디 Point.distance() 정적 (또는 "클래스") 방법이다.


14
이것은 정적 메소드 를 만드는 방법을 보여줍니다 . 실제 질문이 실제로 정적 메소드에 관한 것이 아닌 한 정적 클래스 에 관한 질문에는 대답하지 않습니다 .
Marcus

18
의견 주셔서 감사합니다. 정적 속성과 메서드를 만드는 방법에 대해 설명하며,이를 통해 인스턴스화없이 데이터와 기능을 가진 클래스를 만들 수 있습니다. 특별히 "정적 클래스"는 아니지만 OP의 JavaScript 예제에 설명 된대로 요구 사항을 충족합니다.
Rob Raisch 19

c #에는 버전 2까지 정적 클래스가 없었습니다. 인스턴스화를 막기 위해 c #에만 존재합니다. 자바 스크립트로는 그렇게 할 수 없으므로별로 이해가되지 않습니다.
Simon_Weaver

4
@Simon_Weaver 당신은 자바 스크립트에서 무엇을 할 수 없습니까? 클래스가 인스턴스화되지 않습니까? Typescript는 어쨌든 런타임에 신경 쓰지 않습니다. 작업을 할 때 컴파일 오류가 발생하면 허용되지 않는 것입니다.
Alex

내가 의미하는 것은 버전 2까지 '클래스 수준에서 정적 키워드가 없었습니다 (클래스의 인스턴스를 만들 수 없음을 의미합니다)'였지만 다시 읽으면 내 의견이 그리워졌습니다. 어쨌든 가리 킵니다. OP는 실제로 전체 클래스에 대한 '정적 키워드'를 찾지 않았습니다
Simon_Weaver

20

이 질문은 꽤 오래되었지만 현재 버전의 언어를 활용하는 답변을 남기고 싶습니다. 불행히도 정적 클래스는 여전히 TypeScript에 존재하지 않지만 외부 생성자가 클래스를 인스턴스화하지 못하게하는 전용 생성자를 사용하여 작은 오버 헤드로 유사하게 작동하는 클래스를 작성할 수 있습니다.

class MyStaticClass {
    public static readonly property: number = 42;
    public static myMethod(): void { /* ... */ }
    private constructor() { /* noop */ }
}

이 스 니펫을 사용하면 C #과 유사한 "정적"클래스를 사용하여 내부에서 인스턴스화 할 수 있다는 유일한 단점이 있습니다. 다행히도 개인 생성자로 클래스를 확장 할 수는 없습니다.


9

이것은 한 가지 방법입니다.

class SomeClass {
    private static myStaticVariable = "whatever";
    private static __static_ctor = (() => { /* do static constructor stuff :) */ })();
}

__static_ctor다음은 즉시 호출 된 함수 표현식입니다. Typescript는 생성 된 클래스의 끝에서이를 호출하는 코드를 출력합니다.

업데이트 : 더 이상 정적 멤버가 참조 할 수없는 정적 생성자의 일반 유형의 경우 추가 단계가 필요합니다.

class SomeClass<T> {
    static myStaticVariable = "whatever";
    private ___static_ctor = (() => { var someClass:SomeClass<T> ; /* do static constructor stuff :) */ })();
    private static __static_ctor = SomeClass.prototype.___static_ctor();
}

어쨌든 클래스 뒤에 일반 유형 정적 생성자를 호출 할 수 있습니다 .

class SomeClass<T> {
    static myStaticVariable = "whatever";
    private __static_ctor = (() => { var example: SomeClass<T>; /* do static constructor stuff :) */ })();
}
SomeClass.prototype.__static_ctor();

그냥 NEVER 사용과 기억 this__static_ctor(명백하게) 위.


이 방법으로 여전히 클래스의 생성자를 내 보냅니다.
theycallmemorty

1
"이 방법은"해킹이며, 예상대로 컴파일러의 정상적인 작동을 변경하지 않습니다. class SomeClass {}새로운 이슈가 소개 된 것처럼 언급 할 가치가 거의없는 생성자 도 생성합니다. ;) 참고 : JS 전용 함수에는 객체에서 또는를 통해 호출 할 때 "this"가있는 실제 "생성자"가 없습니다 new. 이것은 "클래스"에 상관없이 존재합니다.
James Wilkins

6

오늘 동일한 사용 사례 (2018 년 7 월 31 일)를 얻었으며 이것이 해결 방법이라는 것을 알았습니다. 그것은 내 연구를 기반으로하며 나를 위해 일했습니다. 예상 -TypeScript에서 다음을 달성합니다.

var myStaticClass = {
    property: 10,
    method: function(){} 
}

나는 이걸했다:

//MyStaticMembers.ts
namespace MyStaticMembers {
        class MyStaticClass {
           static property: number = 10;
           static myMethod() {...}
        }
        export function Property(): number {
           return MyStaticClass.property;
        }
        export function Method(): void {
           return MyStaticClass.myMethod();
        }
     }

따라서 다음과 같이 소비합니다.

//app.ts
/// <reference path="MyStaticMembers.ts" />
    console.log(MyStaticMembers.Property);
    MyStaticMembers.Method();

이것은 나를 위해 일했습니다. 누군가 더 나은 제안이 있으면 모두 들려주세요. 감사...


3

C #과 같은 언어의 정적 클래스는 데이터와 함수를 그룹화하기위한 다른 최상위 구조가 없기 때문에 존재합니다. 그러나 JavaScript에서는 그렇게하므로 사용자처럼 객체를 선언하는 것이 훨씬 더 자연 스럽다. 클래스 구문을 더 모방하기 위해 다음과 같이 메소드를 선언 할 수 있습니다.

const myStaticClass = {
    property: 10,

    method() {

    }
}

1
이 접근 방식이 워크 플로를 방해하지 않습니까? 한편으로는 클래스와 인스턴스를 사용하고 갑자기 기존의 오래된 JS 객체에서 데이터를 다시 선언하기 시작합니다. 정적 클래스를 사용하면 준비가 도움이됩니다.
Kokodoko

4
워크 플로가 지저분하지 않습니다. 반대로, 클래스리스 JavaScrpit 객체를 사용하거나 모듈에서 일반 함수와 상수를 사용하는 것이 매우 편리하다는 것을 알았습니다. 그러나 가능한 한 전역 상태를 피하려고 노력하므로 정적 클래스 변수와 같은 것이 거의 필요하지 않습니다.
Yogu

1

http://www.basarat.com/2013/04/typescript-static-constructors-for.html을 참조 하십시오

이것은 정적 생성자를 '가짜'만드는 방법입니다. 위험이 없습니다 . 참조 코드 플렉스 항목을 참조 하십시오 .

class Test {
    static foo = "orig";

    // Non void static function
    static stat() {
        console.log("Do any static construction here");
        foo = "static initialized";
        // Required to make function non void
        return null;
    }
    // Static variable assignment
    static statrun = Test.stat();
}

// Static construction will have been done:
console.log(Test.foo);

1

이를 달성하는 한 가지 방법은 다른 클래스 내에 클래스의 정적 인스턴스를 두는 것입니다. 예를 들면 다음과 같습니다.

class SystemParams
{
  pageWidth:  number = 8270;
  pageHeight: number = 11690;  
}

class DocLevelParams
{
  totalPages: number = 0;
}

class Wrapper
{ 
  static System: SystemParams = new SystemParams();
  static DocLevel: DocLevelParams = new DocLevelParams();
}

그런 다음 인스턴스를 선언하지 않고도 Wrapper를 사용하여 매개 변수에 액세스 할 수 있습니다. 예를 들면 다음과 같습니다.

Wrapper.System.pageWidth = 1234;
Wrapper.DocLevel.totalPages = 10;

따라서 JavaScript 질문 객체에 설명 된대로 JavaScript 유형 객체의 이점을 얻을 수 있지만 TypeScript 유형을 추가 할 수 있다는 이점이 있습니다. 또한 클래스의 모든 매개 변수 앞에 '정적'을 추가하지 않아도됩니다.


1

ES6 외부 모듈을 사용하면 다음과 같이 달성 할 수 있습니다.

// privately scoped array
let arr = [];

export let ArrayModule = {
    add: x => arr.push(x),
    print: () => console.log(arr),
}

이것은 TSLint [1] [2]에 의해 나쁜 관행으로 간주되는 내부 모듈 및 네임 스페이스의 사용을 막고, 개인 및 공개 범위를 지정하고 원하지 않는 클래스 객체의 초기화를 방지합니다.


0

나는 비슷한 것을 찾고 있었고 Singleton Pattern .

참조 : 싱글 톤 패턴

다른 유형의 파일을로드하기 위해 BulkLoader 클래스에서 작업하고 있으며 싱글 톤 패턴을 사용하려고했습니다. 이렇게하면 주 응용 프로그램 클래스에서 파일을로드하고 다른 클래스에서 쉽게로드 된 파일을 검색 할 수 있습니다.

아래는 TypeScript와 Singleton 패턴을 사용하여 게임의 점수 관리자를 만드는 간단한 예입니다.

SingletonClass {클래스

private static _instance:SingletonClass = new SingletonClass();

private _score:number = 0;

constructor() {
    if(SingletonClass._instance){
        throw new Error("Error: Instantiation failed: Use SingletonDemo.getInstance() instead of new.");
    }
    SingletonClass._instance = this;
}

public static getInstance():SingletonClass
{
    return SingletonClass._instance;
}

public setScore(value:number):void
{
    this._score = value;
}

public getScore():number
{
    return this._score;
}

public addPoints(value:number):void
{
    this._score += value;
}

public removePoints(value:number):void
{
    this._score -= value;
}   }

그런 다음 다른 수업의 어느 곳에서나 싱글 톤에 액세스 할 수 있습니다.

var scoreManager = SingletonClass.getInstance();
scoreManager.setScore(10); scoreManager.addPoints(1);
scoreManager.removePoints(2); console.log( scoreManager.getScore() );

0

키워드 namespace를 사용 하여 변수, 클래스, 메소드 등을 구성 할 수도 있습니다 . doc 참조

namespace Validation {
    export interface StringValidator {
        isAcceptable(s: string): boolean;
    }

    const lettersRegexp = /^[A-Za-z]+$/;
    const numberRegexp = /^[0-9]+$/;

    export class LettersOnlyValidator implements StringValidator {
        isAcceptable(s: string) {
            return lettersRegexp.test(s);
        }
    }

    export class ZipCodeValidator implements StringValidator {
        isAcceptable(s: string) {
            return s.length === 5 && numberRegexp.test(s);
        }
    }
}

위 내용을 참조하십시오 플로리안의 의견 "이되지 않습니다 또한 tslint 당신이 모듈과 네임 스페이스에 대해 더 이상 그렇게 못하게 읽기 여기 :.. palantir.github.io/tslint/rules/no-namespace을"
reggaeguitar
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.