Typescript: 정적 멀버에 대한 닀형성 "this"

에 만든 2015년 12월 01음  Â·  150윔멘튞  Â·  출처: microsoft/TypeScript

상당히 Ʞ볞적읎지만 닀형성의 활성 레윔드 슀타음 몚덞 시슀템을 구현하렀고 할 때 생성자 또는 템플늿/제넀늭곌 핚께 사용할 때 this 륌 쀀수하지 않는 유형 시슀템 묞제에 부딪힙니닀.

나는 읎것에 대핮 읎전에 여Ʞ #5493에 게시했윌며 #5492도 읎 동작을 얞꞉하는 것윌로 볎입니닀.

귞늬고 여Ʞ ë‚Žê°€ 만든 SO 게시묌읎 있습니닀.
http://stackoverflow.com/questions/33443793/create-a-generic-factory-in-typescript-unsolved

추가 녌의륌 위핎 #5493의 예제륌 읎 티쌓윌로 재활용했습니닀. 귞런 것에 대한 갈망곌 토론에 대한 엎망을 나타낮는 공개 티쌓을 원했지만 나뚞지 두 개는 닫혀 있었닀.

닀음은 몚덞을 생성하는 Factory 몚덞을 섀명하는 예입니닀. Factory 에서 돌아였는 BaseModel 륌 사용자 정의하렀멎 읎륌 재정의할 수 있얎알 합니닀. 귞러나 this 는 정적 멀버에서 사용할 수 없Ʞ 때묞에 싀팚합니닀.

// Typically in a library
export interface InstanceConstructor<T extends BaseModel> {
    new(fac: Factory<T>): T;
}

export class Factory<T extends BaseModel> {
    constructor(private cls: InstanceConstructor<T>) {}

    get() {
        return new this.cls(this);
    }
}

export class BaseModel {
    // NOTE: Does not work....
    constructor(private fac: Factory<this>) {}

    refresh() {
        // get returns a new instance, but it should be of
        // type Model, not BaseModel.
        return this.fac.get();
    }
}

// Application Code
export class Model extends BaseModel {
    do() {
        return true;
    }
}

// Kinda sucks that Factory cannot infer the "Model" type
let f = new Factory<Model>(Model);
let a = f.get();

// b is inferred as any here.
let b = a.refresh();

아마도 읎 묞제는 얎늬석고 쉬욎 í•Žê²° 방법읎 있습니닀. 귞러한 팚턎을 달성할 수 있는 방법에 대한 의견을 환영합니닀.

In Discussion Suggestion

가장 유용한 댓Ꞁ

읎 묞제가 닫힌 읎유가 있습니까?

닀형성읎 정적에서 작동하지 않는닀는 사싀은 낮 생각에 읎 Ʞ능을 DOA로 만듭니닀. 나는 지ꞈ까지 읞슀턎슀 멀버에 대핮 닀형성읎 싀제로 필요하지 않았지만 정적 처늬 시슀템읎 쎈Ʞ에 완성되었Ʞ 때묞에 정적에 대핮 몇 죌마닀 필요했습니닀. 읎 Ʞ능읎 발표되었을 때 나는 맀우 Ʞ뻀지만, 나쀑에 읎 Ʞ능읎 읞슀턎슀 구성원에게만 작동한닀는 사싀을 알고는 싀망했습니닀.

사용 사례는 맀우 Ʞ볞적읎고 맀우 음반적입니닀. ê°„ë‹ší•œ 팩토늬 메소드륌 고렀하십시였.

class Animal
{
    static create(): this
    {
        return new this();
    }
}

class Bunny extends Animal
{
    hop()
    {
    }
}

Bunny.create().hop() // Type error!! Come on!!

읎 시점에서 저는 각 상속자에서 못생ꞎ 캐슀팅읎나 static create() 메소드륌 사용했습니닀. 읎 Ʞ능읎 없윌멎 얞얎의 완성도가 상당히 떚얎지는 것처럌 볎입니닀.

몚든 150 댓Ꞁ

낮 볎튞의 크Ʞ와 몚양은 맀우 비슷합니닀! 얎읎!

슈퍌큎래슀의 팩토늬 메소드는 서람큎래슀의 새 읞슀턎슀륌 반환합니닀. 낮 윔드의 Ʞ능은 작동하지만 반환 유형을 캐슀팅핎알 합니닀.

class Parent {
    public static deserialize(data: Object): any { ... create new instance ... }
    // Can't return a this type from statics! ^^^ :(
}

class Child extends Parent { ... }

let data = { ... };
let aChild: Child = Child.deserialize(data);
//           ^^^ Requires a cast as type cannot be inferred.

나는 였늘도 읎 묞제에 부딪쳀닀!

수정 솔룚션은 자식 유형을 Ʞ볞 큎래슀륌 확장하는 제넀늭윌로 전달하는 것입니닀. 읎는 제가 당분간 적용하는 솔룚션입니닀.

class Parent {
    static create<T extends Parent>(): T {
        let t = new this();

        return <T>t;
    }
}

class Child extends Parent {
    field: string;
}

let b = Child.create<Child>();

읎 묞제가 닫힌 읎유가 있습니까?

닀형성읎 정적에서 작동하지 않는닀는 사싀은 낮 생각에 읎 Ʞ능을 DOA로 만듭니닀. 나는 지ꞈ까지 읞슀턎슀 멀버에 대핮 닀형성읎 싀제로 필요하지 않았지만 정적 처늬 시슀템읎 쎈Ʞ에 완성되었Ʞ 때묞에 정적에 대핮 몇 죌마닀 필요했습니닀. 읎 Ʞ능읎 발표되었을 때 나는 맀우 Ʞ뻀지만, 나쀑에 읎 Ʞ능읎 읞슀턎슀 구성원에게만 작동한닀는 사싀을 알고는 싀망했습니닀.

사용 사례는 맀우 Ʞ볞적읎고 맀우 음반적입니닀. ê°„ë‹ší•œ 팩토늬 메소드륌 고렀하십시였.

class Animal
{
    static create(): this
    {
        return new this();
    }
}

class Bunny extends Animal
{
    hop()
    {
    }
}

Bunny.create().hop() // Type error!! Come on!!

읎 시점에서 저는 각 상속자에서 못생ꞎ 캐슀팅읎나 static create() 메소드륌 사용했습니닀. 읎 Ʞ능읎 없윌멎 얞얎의 완성도가 상당히 떚얎지는 것처럌 볎입니닀.

@paul-go 묞제가 종료되지 않았습니닀... ?

@paul-go 읎 묞제에도 좌절했지만 아래는 ë‚Žê°€ 찟은 가장 안정적읞 í•Žê²° 방법입니닀. 각 Animal 하위 큎래슀는 super.create()륌 혞출하고 결곌륌 핎당 유형윌로 캐슀팅핎알 합니닀. 별거 아니고 읎것윌로 쉜게 제거할 수 있는 원 띌읎너가 추가되었습니닀.

컎파음러, 읞텔늬섌슀, 귞늬고 가장 쀑요한 토끌는 몚두 만족합니닀.

class Animal {
    public static create<T extends Animal>(): T {
        let TClass = this.constructor.prototype;
        return <T>( new TClass() );
    }
}

class Bunny extends Animal {    
    public static create(): Bunny {
        return <Bunny>super.create();
    }

    public hop(): void {
        console.log(" Hoppp!! :) ");
    }
}

Bunny.create().hop();

         \\
          \\_ " See? I am now a happy Bunny! "
           (')   " Don't be so hostile! "
          / )=           " :P "
        o( )_


@RyanCavanaugh 웁슀 ... 얎쩐지 읎걞 #5862 와 혌동했넀요 ... 전투도끌 공격 죄송합니닀 :-)

@Think7 예 ... 따띌서 "각 상속자에서 못생ꞎ 캐슀팅 또는 쓰레Ʞ 정적 create() 메서드에 정렬". 당신읎 띌읎람러늬 개발자읎고 최종 사용자가 당신에게서 상속받은 큎래슀에서 많은 유형의 정적 메소드륌 구현하도록 강제할 수는 없지만 ꜀ 얎렵습니닀.

띌욞. 윔드 아래의 몚든 것을 완전히 놓쳀습니닀. D

귞만한 가치가있었습니닀. 토끌륌 귞렀알합니닀.

:+1: 토끌

:토끌: :하튾:

+1, ꌭ 볎고 싶습니닀.

읎 죌제에 대한 토론 업데읎튞가 있었습니까?

귞것은 우늬의 엄청난 제안 백로귞에 ë‚šì•„ 있습니닀.

Javascript는 읎믞 읎러한 팚턎에서 올바륎게 작동합니닀. TS도 따륌 수 있닀멎 많은 상용구/추가 윔드에서 우늬륌 구할 수 있습니닀. "몚덞 팹턮"은 ꜀ 표쀀적읞 팚턎입니닀. 저는 TS가 읎에 대핮 JS가 하는 것처럌 작동할 것윌로 Ʞ대합니닀.

나는 또한 닀륞 몚든 사람듀곌 동음한 "CRUD 몚덞" 읎유로 읎 Ʞ능을 정말 원합니닀. 읞슀턎슀 메서드볎닀 정적 메서드에 필요합니닀.

읎것은 #8164에 섀명된 묞제에 대한 깔끔한 솔룚션을 제공합니닀.

재정의 및 제넀늭읎 포핚된 "솔룚션"읎 있는 것은 좋지만 여Ʞ에서 싀제로 핎결하는 것은 없습니닀. 읎 Ʞ능을 사용하는 전첎 목적은 읎러한 재정의/캐슀팅을 플하고 this 반환 방식곌의 음ꎀ성을 만드는 것입니닀. 유형은 읞슀턎슀 메소드에서 처늬됩니닀.

저는 Sequelize 4.0에 대한 타읎핑 작업을 하고 있윌며 Model 큎래슀륌 하위 큎래슀로 분류하는 ì ‘ê·Œ 방식을 사용합니닀. 핎당 Model 큎래슀에는 findById() 등곌 같은 수많은 정적 메서드가 있습니닀. 묌론 Model 륌 반환하지 않지만 정적 컚텍슀튞에서 this 띌는 하위 큎래슀륌 반환합니닀.

abstract class Model {
    public static tableName: string;
    public static findById(id: number): this { // error: a this type is only available in a non-static member of a class or interface 
        const rows = db.query(`SELECT * FROM ${this.tableName} WHERE id = ?`, [id]);
        const instance = new this();
        for (const column of Object.keys(rows[0])) {
            instance[column] = rows[0][column];
        }
        return instance;        
    }
}

class User extends Model {
    public static tableName = 'users';
    public username: string;    
}

const user = User.findById(1); // user instanceof User

현재 입력할 수 없습니닀. Sequelize는 Node용 _the_ ORM읎고 입력할 수 없닀는 것읎 아쉜습니닀. 읎 Ʞ능읎 정말 필요합니닀. 유음한 방법은 읎러한 핚수 쀑 하나륌 혞출할 때마닀 캐슀튞하거나 몚든 핚수륌 재정의하고 반환 유형을 조정하고 super.method() 혞출만 하는 것입니닀.

또한 정적 멀버는 제넀늭 형식 읞수륌 ì°žì¡°í•  수 없닀는 것곌 ꎀ렚읎 있습니닀. 음부 메서드는 형식 읞수륌 통핎 입력할 수 있는 몚덞에 대한 속성의 개첎 늬터럎을 사용하지만 읞슀턎슀 멀버만 사용할 수 있습니닀.

😰 읎게 아직도 수정/추가가 안되었닀는게 믿Ʞ지 않는닀.....

우늬는 읎것을 잘 사용할 수 있습니닀:

declare class NSObject {
    init(): this;
    static alloc(): this;
}

declare class UIButton extends NSObject {
}

let btn: UIButton = UIButton.alloc().init();

닀음은 ë‚Žê°€ 작업했윌멎 하는 사용 사례입니닀(https://github.com/Microsoft/TypeScript/issues/9775에서 마읎귞레읎션했윌며 읎륌 위핎 마감했습니닀).

현재 생성자의 맀개변수는 this 유형을 사용할 수 없습니닀.

class C<T> {
    constructor(
        public transformParam: (self: this) => T // not works
    ){
    }
    public transformMethod(self: this) : T { // works
        return undefined;
    }
}

예상됚: 생성자 맀개변수에 사용할 수 있습니닀.

핎결하고자 하는 묞제:

  • 동음한 윔드륌 재사용하는 닀륞 유찜한 API 죌변에서 낮 유찜한 API륌 Ʞ반윌로 할 수 있습니닀.
class TheirFluentApi {
    totallyUnrelated(): TheirFluentApi {
        return this;
    }
}

class MyFluentApi<FluentApi> {
    constructor(
        public toNextApi: (self: this) => FluentApi // let's imagine it works
    ){
    }
    one(): FluentApi {
        return this.toNextApi(this);
    }
    another(): FluentApi {
        return this.toNextApi(this);
    }
}

// self based fluent API;
const selfBased = new MyFluentApi(this => this);
selfBased.one().another();

// foreign based fluent API:
const foreignBased = new MyFluentApi(this => new TheirFluentApi());
foreignBased.one().totallyUnrelated();

믞래 지향적읞 í•Žê²° 방법:

class Foo {

    foo() { }

    static create<T extends Foo>(): Foo & T {
        return new this() as Foo & T;
    }
}

class Bar extends Foo {

    bar() {}
}

class Baz extends Bar {

    baz() {}
}

Baz.create<Baz>().foo()
Baz.create<Baz>().bar()
Baz.create<Baz>().baz()

읎렇게 하멎 TypeScript가 정적 멀버에 대핮 this 륌 지원하멎 새 사용자 윔드는 Baz.create() 대신 Baz.create<Baz>() 가 되는 반멎 읎전 사용자 윔드는 정상적윌로 작동합니닀. :웃닀:

읎것은 정말 필요합니닀! 특히 읞슀턎슀륌 반환하는 정적 메서드가 있는 DAO의 겜우. 대부분은 (저장, 가젞였Ʞ, 업데읎튞 등...) Ʞ볞 DAO에 정의되얎 있습니닀.

정적 메소드의 this 유형읎 큎래슀 유형읎 아니띌 핎당 큎래슀로 핎석되는(예: typeof ) 혌란을 음윌킬 수 있닀고 말할 수 있습니닀.

싀제 JS에서 유형에 대한 정적 메소드륌 혞출하멎 핚수 낎부에서 this 가 큎래슀의 읞슀턎슀가 아니띌 큎래슀가 됩니닀... 귞래서 음ꎀ성읎 없습니닀.

귞러나 사람듀의 직ꎀ윌로는 정적 메서드에서 this 반환 유형을 볌 때 가장 뚌저 팝업되는 것읎 읞슀턎슀 유형읎띌고 생각합니닀...

@shlomiassaf 음ꎀ성읎 없습니닀. User와 같은 핚수의 반환 유형윌로 큎래슀륌 지정하멎 반환 유형은 사용자의 읞슀턎슀가 됩니닀. 정확히 동음합니닀. 정적 메서드에서 this의 반환 유형을 정의할 때 반환 유형은 this(큎래슀의 읞슀턎슀)의 읞슀턎슀가 됩니닀. 큎래슀 자첎륌 반환하는 메서드는 typeof this로 몚덞링할 수 있습니닀.

@felixfbecker 읎것은 완전히 ꎀ점의 묞제읎며, 읎것읎 당신읎 귞것을 볎는 방식을 선택하는 것입니닀.

녌늬륌 추론할 수 있도록 JS에서 ì–Žë–€ 음읎 발생하는지 조사핎 볎겠습니닀.

class Example {
  myFunc(): this {
    return this; 
  }

  static myFuncStatic(): this {
    return this;   // this === Example
  }
}

new Example().myFunc() //  instanceof Exapmle === true
Example.myFuncStatic() // === Example

읎제 싀제 런타임에서 this 는 핚수의 제한된 컚텍슀튞입니닀. 읎것은 읞터페읎슀와 같은 유찜한 API에서 발생하는 음읎며 닀형성읎 Ʞ능은 JS 작동 방식곌 음치하는 올바륞 유형을 반환하여 도움을 쀍니닀. this 륌 반환하는 Ʞ볞 큎래슀는 파생 큎래슀에서 생성한 읞슀턎슀륌 반환합니닀. 읎 Ʞ능은 싀제로 수정 사항입니닀.

요앜하자멎:
프로토타입(읞슀턎슀)의 음부로 정의된 this 륌 반환하는 메서드는 읞슀턎슀륌 반환핎알 합니닀.

계속핎서 핎당 녌늬륌 사용하여 큎래슀 유형(프로토타입)의 음부로 정의된 this 륌 반환하는 메서드는 큎래슀 유형읞 겜계 컚텍슀튞륌 반환핎알 합니닀.

닀시 말하지만, 펞견도, 의견도, 닚순한 사싀도 없습니닀.

직감적윌로는 정적 핚수에서 반환된 this 가 유형 낎에 정의되얎 있Ʞ 때묞에 읞슀턎슀륌 나타낮는 것읎 펾할 것입니닀. 하지만 귞게 전부입니닀. 닀륞 사람듀은 닀륎게 생각할 수 있고 우늬는 귞듀의 잘못을 말할 수 없습니닀.

묞제는 큎래슀 읞슀턎슀륌 반환하는 정적 메서드와 큎래슀 자첎(typeof this)륌 반환하는 정적 메서드륌 몚두 입력할 수 있얎알 한닀는 것입니닀. 귀하의 녌늬는 JS ꎀ점에서 의믞가 있지만 여Ʞ에서는 return _types_에 대핮 읎알Ʞ하고 있윌며 TypeScript 및 Ʞ타 얞얎에서 큎래슀륌 반환 유형(여Ʞ서는 this)윌로 사용하는 것은 항상 큎래슀의 읞슀턎슀륌 의믞합니닀. 싀제 큎래슀륌 반환하Ʞ 위핎 typeof 연산자가 있습니닀.

@felixfbecker 읎것은 또 닀륞 묞제륌 알Ʞ합니닀!

this 유형읎 읞슀턎슀 유형읞 겜우 정적 메소드 볞묞에서 this 킀워드가 찞조하는 것곌 닀늅니닀. return this 는 typeof this 의 핚수 반환 유형을 생성합니닀. 읎는 완전히 읎상합니닀!

아니, 귞렇지 않습니닀. 닀음곌 같은 방법을 정의할 때

getUser(): User {
  ...
}

User 큎래슀가 아닌 User _instance_륌 닀시 받을 것윌로 예상합니닀(읎것읎 typeof 의 용도입니닀). 몚든 유형의 얞얎에서 작동하는 방식입니닀. 유형 의믞론은 닚순히 런타임 의믞론곌 닀늅니닀.

this 또는 static 킀워드륌 func의 생성자로 사용하여 자식 큎래슀륌 조작하지 않는 읎유는 묎엇입니까?

class Model {
  static find():this[] {
    return [new this("prop")]; // or new static(...)
  }
}

class Entity extends Model {
  constructor(public prop:string) {}
}

Entity.find().map(x => console.log(x.prop));

귞늬고 읎것을 JS의 예와 비교하멎 올바륎게 작동하는 것을 볌 수 있습니닀.

class Model {
  static find() { 
    return [new this] 
  }
}

class Entity extends Model {
  constructor(prop) {
    this.prop = prop;
  }
}

Entity.find().map(x => console.log(x.prop))

정적 메서드에 this 유형을 사용할 수 없습니닀. 읎것읎 묞제의 전첎 룚튞띌고 생각합니닀.

@felixfbecker

읎걞 고렀하섞요:

class Greeter {
    static getHandle(): this {
        return this;
    }
}

읎 유형 죌석은 직ꎀ적읎지만 정적 메서드의 this 유형읎 큎래슀 읞슀턎슀읞 겜우 올바륎지 않습니닀. this 킀워드는 정적 메서드에서 typeof this 유형을 가집니닀!

나는 this 가 큎래슀 유형읎 아니띌 읞슀턎슀 유형을 ì°žì¡°í•Žì•Œ 한닀고 생각합니닀. 왜냐하멎 우늬는 읞슀턎슀 유형( typeof X )에서 큎래슀 유형에 대한 찞조륌 얻을 수 있지만 ê·ž 반대의 겜우는 불가능하Ʞ 때묞입니닀( instancetypeof X ?)

@xealot 좋아요, this static 킀워드륌 사용하지 않겠습니까? 귞러나 JS 정적 컚텍슀튞의 this 는 여전히 생성자륌 가늬킵니닀.

@izatop 예, 생성된 자바슀크늜튞가 제대로 또는 부적절하게 작동합니닀. 귞러나 읎것은 Javascript에 ꎀ한 것읎 아닙니닀. 불만은 Javascript ì–žì–Žê°€ 읎 팚턎을 허용하지 않는닀는 것읎 아니띌 Typescript의 유형 시슀템읎 허용하지 않는닀는 것입니닀.

Typescript는 정적 멀버에 대한 닀형성 this 유형을 허용하지 ì•Šêž° 때묞에 읎 팚턎윌로 유형 안전성을 유지할 수 없습니닀. 여Ʞ에는 static 킀워드와 constructor 로 정의된 큎래슀 메서드가 포핚됩니닀.

놀읎터 링크

@LPGhatguy 귌데 제 읎전 댓Ꞁ 잘 읜윌셚죠?! 반환 유형읎 User 읞 메서드가 있는 겜우 return User; 가 아니띌 $ return new User(); 가 예상됩니닀. 같은 방식윌로 this 의 반환 값은 정적 메서드에서 return new this(); 륌 의믞핎알 합니닀. 비정적 메서드에서는 닀륎지만 this 는 항상 개첎읎므로 읞슀턎슀화할 수 없습니닀. 귞러나 ê²°êµ­ 우늬는 Ʞ볞적윌로 읎것읎 typeof 때묞에 읎것읎 최고의 구묞읎고 읎 Ʞ능읎 TS에서 많읎 필요하닀는 데 동의합니닀.

@xealot TypeScript가 닀형성 this 을 허용하지 않는 것을 읎핎하지만 읎 Ʞ능을 TS에 추가하지 않는 읎유륌 묻겠습니닀.

닀음읎 읎 묞제의 몚든 사용 사례에 대핮 작동하는지 몚륎겠지만 유형 추론 시슀템의 현명한 사용곌 핚께 정적 메서드에서 this: 유형을 사용하멎 타자. 믿을 수 없을 정도로 읜을 수는 없지만 자식 큎래슀에서 정적 메서드륌 재정의하지 않고도 작업을 수행합니닀.

[email protected] 에서 작동

닀음을 고렀하섞요 ;

// IModelClass is just here to describe an instanciator
// since we can't use typeof T (unfortunately) with
// the generic type system.
interface IModelClass<T extends Model> {
  new (...a: any[]): T

  // unfortunately, we have to put here again all the typing information
  // of the static members (without static, since we are describing a class, not an instance)

  some_member: string
  create<T extends Model>(this: IModelClass<T>): T
}

class Model {

  // Here we use this with the IModel<T> to force the
  // type system to use T as our current caller.

  static some_member: string

  // When we call Dog.create() below, T is thus resolved
  // to Dog *and stays that way*
  // If typeof worked on generic types (it doesn't), we could have defined this method
  // instead as 
  // static create<T extends Model>(this: typeof T): T { ... }
  static create<T extends Model>(this: IModelClass<T>): T {
    return new this() // whatever you fancy here
  }
}

class Dog extends Model {
  bark() { }
}

class Cat extends Model {
  meow() { }
}

// Everything should be typed here, and we didn't have to redefine static methods
// in Dog nor Cat
let dog = Dog.create()
dog.bark()
let cat = Cat.create()
cat.meow()

@ceymard this 가 맀개변수로 지정되는 읎유는 묎엇입니까?

읎것은 핚수에 대핮 읎 맀개변수륌 정의할 수 있는 typescript 2.0.0곌 핚께 제공되는 https://github.com/Microsoft/TypeScript/issues/3694 때묞입니닀 this 묞제 및 Ʞ능의 잘못된 사용을 방지하Ʞ 위핎)

정적 메서드뿐만 아니띌 메서드에서도 사용할 수 있윌며 우늬가 제공하는 this 륌 비교하도록 강제하여 유형 유추Ʞ륌 "도움"하는 데 사용하는 것곌 같읎 정말 재믞있는 것을 허용한닀는 것읎 밝혀졌습니닀. (아읎몚덞) 사용 쀑읞 것(개 또는 고양읎)윌로 읎동합니닀. 귞런 닀음 T 에 대한 올바륞 유형을 "추잡"하고 읎륌 사용하므로 핚수륌 올바륎게 입력합니닀.

( this 는 typescript 컎파음러가 읎핎하는 _special_ 맀개변수읎며 핚수에 하나륌 더 추가하지 않습니닀.)

구묞읎 <this extends Whatever> 와 같은 것읎띌고 생각했습니닀. create() 에 닀륞 맀개변수가 있는 겜우에도 여전히 작동할까요?

전적윌로

또한 읎것읎 낎장 유형에 쀑요하닀는 점을 지적하고 싶었습니닀.
예륌 듀얎 Array 륌 하위 큎래슀로 지정하멎 하위 큎래슀의 from() 메서드는 Array 가 아니띌 하위 큎래슀의 읞슀턎슀륌 반환합니닀.

class Task {}
class TaskList extends Array<Task> {
  public execute() {}
}
// actually returns instance of TaskList at runtime
const tasks = TaskList.from([new Task()])
tasks.execute() // error, method execute does not exist on type Array

읎 묞제에 대한 업데읎튞가 있습니까? 읎 Ʞ능은 우늬 팀의 TypeScript 겜험을 크게 향상시킬 것입니닀.

읎것은 ORM에서 음반적윌로 사용되는 팚턎읎고 많은 윔드가 컎파음러 및 유형 시슀템읎 생각하는 것곌 맀우 닀륎게 동작하Ʞ 때묞에 닀소 쀑요합니닀.

나는 반론에 반대하는 반론을 제Ʞ할 것입니닀.

@shlomiassaf 가 지적했듯읎 this 륌 정적 멀버에 허용하멎 this 가 정적 메서드와 읞슀턎슀 메서드에서 닀륞 것을 의믞하Ʞ 때묞에 혌동을 음윌킬 수 있습니닀. 또한 유형 죌석의 $# this this 는 의믞가 닀늅니닀. 새 킀워드륌 도입하여 읎러한 혌란을 플할 수 있지만 새 킀워드의 비용은 높습니닀.

귞늬고 현재 TypeScript에는 쉬욎 í•Žê²° 방법읎 있습니닀. @ceymard 는 읎믞 귞것을 볎여죌었습니닀 . 귞늬고 정적 메서드의 런타임 의믞륌 포착하Ʞ 때묞에 귞의 ì ‘ê·Œ 방식을 선혞합니닀. 읎 윔드륌 고렀하십시였.

class A {
  constructor() {}
  static create<T extends A>(this: {new (): T}) {} // constructor signature is exactly the same as A's
}

class B extends A {
  constructor(a: number) {
    super()
  }
}

B.create() // correctly trigger compile error here

닀형성읎 지원되는 겜우 컎파음러는 class B extends A 였류륌 볎고핎알 합니닀. 귞러나 읎것은 획Ʞ적읞 변화입니닀.

@HerringtonDarkholme 혌란읎 볎읎지 않습니닀 this 의 반환 유형은 정확히 return new this() 에서 Ʞ대하는 것입니닀. 잠재적윌로 읎륌 위핎 self 륌 사용할 수 있지만 닀륞 킀워드(출력을 생성하는 데 사용된 킀워드가 아닌)륌 도입하는 것읎 더 혌란슀러워 볎입니닀. 우늬는 읎믞 귞것을 반환 유형윌로 사용하고 있습니닀. 유음한(귞러나 큰) 묞제는 정적 멀버에서 지원되지 않는닀는 것입니닀.

컎파음러는 프로귞래뚞에게 í•Žê²° 방법을 요구핎서는 안 됩니닀. TypeScript는 "향상된 JavaScript"여알 하며 읎 겜우에는 사싀읎 아닙니닀. 수백만 개의 였류륌 생성하지 않도록 윔드에 대핮 복잡한 í•Žê²° 방법을 수행핎알 합니닀. 현재 버전에서 얎떻게든 달성할 수 있닀는 것은 좋지만 귞렇닀고 í•Žì„œ 묞제가 없고 수정읎 필요하지 않닀는 의믞는 아닙니닀.

귞렇닀멎 this 의 반환 유형읎 메서드 볞묞의 this 유형곌 닀륞 읎유는 묎엇입니까?
읎 윔드가 싀팚하는 읎유는 묎엇입니까? 새로욎 사람에게 귞것을 얎떻게 섀명할 수 있습니까?

class A {
  static create(): this {
     return this
  }
}

JavaScript의 상위 집합읎 읎것을 받아듀읎지 못하는 읎유는 묎엇입니까?

class A {
  static create() {
    return new this()
  }
}

abstract class B extends A {}

사싀, 귞러멎 닀륞 킀워드륌 도입핎알 할 수도 있습니닀. self 또는 instance 수 있습니닀.

@HerringtonDarkholme 쎈볎자에게 섀명하는 방법은 닀음곌 같습니닀.
당신읎 할 때

class A {
  static whatever(): B {
    return new B();
  }
}

B B 의 읞슀턎슀륌 반환핎알 핚을 의믞합니닀. 큎래슀 자첎륌 반환하렀멎 닀음을 사용핎알 합니닀.

class B {
 static whatever(): typeof B {
   return B;
 }
}

읎제 JavaScript에서와 마찬가지로 정적 멀버의 this 는 큎래슀륌 찞조합니닀. 따띌서 정적 메서드에서 this 의 반환 유형을 사용하는 겜우 큎래슀의 읞슀턎슀륌 반환핎알 합니닀.

class A {
  static whatever(): this {
    return new this();
  }
}

큎래슀 자첎륌 반환하렀멎 typeof this 륌 사용핎알 합니닀.

class A {
  static whatever(): typeof this {
    return this;
  }
}

귞것읎 바로 ê·ž 읎후로 TS에서 유형읎 읎믞 작동하는 방식입니닀. 큎래슀로 입력하는 겜우 TS는 읞슀턎슀륌 예상합니닀. 큎래슀 유형 자첎에 대핮 입력하렀멎 typeof 륌 사용핎알 합니닀.

귞런 닀음 this 가 메서드 볞묞에서 동음한 의믞륌 갖지 않는 읎유륌 묻겠습니닀. 읞슀턎슀 메소드 유형 죌석의 this this 와 동음한 의믞륌 갖는 겜우 정적 메소드와 동음하지 않은 읎유는 묎엇입니까?

우늬는 딜레마에 직멎핎 있윌며 ì„ž 가지 옵션읎 있습니닀.

  1. make this 는 닀륞 컚텍슀튞에서 닀륞 것을 의믞합니닀(혌란).
  2. self 또는 static 와 같은 새 킀워드 도입
  3. 프로귞래뚞가 더 읎상한 유형 죌석을 작성하게 하십시였(음부 사용자에게 영향을 믞칚)

정적 메서드 정의의 런타임 의믞륌 반영하Ʞ 때묞에 ì„ž 번짞 ì ‘ê·Œ 방식을 선혞합니닀.
또한 사읎튞륌 정의하는 대신 사용 사읎튞에서 였류륌 찟아냅니닀. 슉, 읎 죌석 에서와 같읎 였류는 class B extends A B.create 에서 볎고됩니닀. 읎 겜우 사용 사읎튞 였류가 더 정확합니닀. ( this 륌 찞조하는 정적 메서드륌 ì„ ì–ží•œ 닀음 추상 하위 큎래슀륌 선얞한닀고 가정).

귞늬고 가장 쀑요한 것은 새로욎 Ʞ능에 대한 ì–žì–Ž 제안읎 필요하지 않닀는 것입니닀.

싀제로 선혞도는 사람곌 닀늅니닀. 하지만 적얎도 읎와 같은 볎닀 상섞한 제안을 볎고 싶습니닀. 추상 큎래슀 할당 가능성, 하위 큎래슀 혞환되지 않는 생성자 서명 및 였류 볎고 전략곌 같읎 í•Žê²°í•Žì•Œ 할 묞제가 많습니닀.

@HerringtonDarkholme 읞슀턎슀 메소드의 겜우 런타임 this 는 큎래슀가 아닌 객첎 읞슀턎슀읎Ʞ 때묞에 혌동의 여지가 없습니닀. this 유형은 말 귞대로 런타임 this 읎며 닀륞 옵션읎 없습니닀. 정적의 겜우 객첎 지향 프로귞래밍 얞얎의 닀륞 큎래슀 죌석처럌 작동하지만 큎래슀로 죌석을 추가하멎 읞슀턎슀가 닀시 돌아올 것윌로 예상됩니닀. 또한 TS의 겜우 JavaScript 큎래슀도 객첎읎Ʞ 때묞에 typeof 큎래슀로 입력하멎 늬터럎 큎래슀륌 닀시 얻을 수 있습니닀.

낮 말은, this 반환 유형을 구현했을 때 정적 쌀읎슀에 대핎서도 생각하고 대신 사용자가 읞슀턎슀 메소드에 대핮 항상 typeof this 륌 작성하도록 요구했을 때 아마도 더 음ꎀ성읎 있었을 것입니닀. 귞러나 ê·ž 결정은 ê·ž 당시에 낎렀졌윌므로 지ꞈ ìž‘ì—…í•Žì•Œ 하며, ë‚Žê°€ 말했듯읎 읞슀턎슀 메소드의 this 는 닀륞 유형을 생성하지 ì•Šêž° 때묞에 혌동의 여지륌 낚Ʞ지 않습니닀(큎래슀와 달늬 정적 유형곌 읞슀턎슀 유형읎 있음), 따띌서 읎 겜우 구별되며 누구에게도 혌동을 죌지 않습니닀.

좋아요, 아묎도 this 로 혌동하지 않을 것읎띌고 가정하겠습니닀. 추상 큎래슀 할당 가능성은 얎떻습니까?

메소드의 정적은 닀소 임의적입니닀. 몚든 핚수는 속성곌 메서드륌 가질 수 있습니닀. new 로도 혞출할 수 있는 겜우 읎러한 속성곌 메서드륌 static 로 혞출하도록 선택합니닀. 읎제 읎 규칙읎 ECMAScript에 확고하게 자늬 잡았습니닀.

@HerringtonDarkholme this 륌 사용하멎 혌동을 음윌킬 수 있닀는 것은 의심의 여지가 없습니닀. 귞러나 this 륌 사용하는 데 잘못된 것읎 없Ʞ 때묞에 특히 닀양한 대안에 대한 당신의 Ʞ믌한 비용 펞익 분석을 고렀할 때 완벜하게 ꎜ찮닀고 말하고 싶습니닀. this 가 가장 나쁜 대안읎띌고 생각합니닀.

나는 닚지 낮 원래 게시묌에서 읎 슀레드륌 따띌잡윌렀고 녞력했는데, 아마도 읎것읎 궀도에서 조ꞈ ë²—ì–Žë‚œ 것 같은 느낌읎 듭니닀.

명확히 하자멎 this 유형 죌석읎 생성자, 특히 음반/템플늿윌로 사용될 때 닀형성읎 되Ʞ륌 바띌는 것입니닀. @shlomiassaf 및 @HerringtonDarkholme 와 ꎀ렚하여 저는 static 메서드가 있는 예제가 혌란슀러욞 수 있윌며 읎 묞제의 의도가 아니띌고 생각합니닀.

자죌 귞렇게 생각되지는 않지만 큎래슀의 생성자는 정적입니닀. 더 명확한 섀명곌 핚께 닀시 게시할 예제는 정적 메서드에서 this 륌 선얞하지 않고 대신 정적 메서드의 유형 죌석에서 제넀늭을 통핎 나쀑에 사용할 수 있도록 this 륌 선얞합니닀. .

찚읎점은 this 가 정적 메서드에서 슉시 계산되는 것을 원하지 않고 믞래에는 동적 메서드에서 계산된닀는 것입니닀.

// START LIBRARY CODE
// Constrains the constructor to one that creates things that extend from BaseModel
interface ModelConstructor<T extends BaseModel> {
    new(fac: ModelAPI<T>): T;
}

class ModelAPI<T extends BaseModel> {
    // skipping the use of a ModelConstructor in favor of typeof does not work
    // constructor(private modelType: typeof T) {}
    constructor(private modelType: ModelConstructor<T>) {}

    create() {
        return new this.modelType(this);
    }
}

class BaseModel {
    // This is where "polymorphic `this`" in static members matters. We are 
    // trying to say that the ModelAPI should create instances of whatever 
    // the *current* class is, not the BaseModel class. Much like it would 
    // at runtime.
    constructor(private fac: ModelAPI<this>) {}

    reload() {
        // `reload()` returns a new instance of type Any, incorrect
        return this.fac.create();
    }
}
// END LIBRARY CODE

// START APPLICATION CODE
// Create a custom model class with custom behavior
class Model extends BaseModel {}

// Create an instance of the model API that produces my custom type
let api = new ModelAPI<Model>(Model);  // ModalAPI should be able to infer "<Model>" from the constructor?
let modelInst = api.create();  // Returns type of Model, correct
let reset = modelInst.reload();  // Returns type of Any, incorrect
// END APPLICATION CODE

읎것읎 혌란슀럜닀고 생각하는 사람에게는 Ꞁ쎄요, 맀우 간닚하지 않닀는 데 동의합니닀. 귞러나 BaseModel 의 생성자에서 this 륌 사용하는 것은 싀제로 정적 사용읎 아니띌 나쀑에 계산되는 지연 사용입니닀. 귞러나 정적 메서드(생성자 포핚)는 귞런 식윌로 작동하지 않습니닀.

런타임에 읎 몚든 것읎 예상대로 작동한닀고 생각합니닀. 귞러나 유형 시슀템은 읎 특정 팚턎을 몚덞링할 수 없습니닀. 읎 묞제가 공개된 읎유는 typescript가 자바슀크늜튞 팚턎을 몚덞링할 수 없Ʞ 때묞입니닀.

꞉하게 작성한 댓Ꞁ읎 혌란슀럜닀멎 죄송합니닀.

@xealot 요점은 알지만 정적 메서드에 대한 닀형성 this 을 구첎적윌로 제안한 닀륞 묞제는 읎 묞제의 복제볞윌로 닫혔습니닀. TS의 수정 사항읎 두 사용 사례륌 몚두 활성화할 것읎띌고 가정합니닀.

정확한 사용 사례는 묎엇입니까? 아마도 '읎것' 솔룚션읎멎 충분할 것입니닀.

나는 귞것을 성공윌로 사용자 정의 ORM 띌읎람러늬에서 사용합니닀.
륎쥬. 10월 20음 2016 à 19:15, Tom Marius [email protected] a
에크늬튞 :

읎것은 음반적윌로 사용되Ʞ 때묞에 닀소 쀑요합니닀.
ORM의 팚턎곌 많은 윔드가
컎파음러와 유형 시슀템은 귞래알 한닀고 생각합니닀.

—
당신읎 얞꞉되었Ʞ 때묞에 읎것을 받는 것입니닀.
읎 읎메음에 직접 답장하고 GitHub에서 확읞하섞요.
https://github.com/Microsoft/TypeScript/issues/5863#issuecomment -255169194,
또는 슀레드 음소거
https://github.com/notifications/unsubscribe-auth/AAtAoRHc45B386xdNhuCLB8iW6i82e7Uks5q16GzgaJpZM4GsmOH
.

@ceymard 와 @HerringtonDarkholme에게 감사드늜니닀.

static create<T extends A>(this: {new (): T}) { return new this(); } 가 나륌 위핎 속임수륌 썌습니닀 👍

얞뜻 볎Ʞ에는 static create(): this { return new this(); } 볎닀 더 몚혞하지만 적얎도 맞습니닀! 정적 메서드 낎에서 this 유형을 정확하게 캡처합니닀.

가장 많읎 찬성되거나 댓Ꞁ읎 달늬지 않더띌도 읎것읎 얎떻게든 우선 순위륌 지정할 수 있Ʞ륌 바랍니닀. 예륌 듀얎 올바륞 유형을 얻Ʞ 위핎 유형 읞수륌 사용핎알 하는 것은 맀우 성가신 음입니닀.

let u = User.create<User>();

싀제로 가능한 겜우:

let u = User.create();

귞늬고 static읎 때때로 읞슀턎슀 유형을 찞조하는 것은 불가플합니닀.

정적 멀버의 this 유형읎 큎래슀의 정적 ìž¡ë©Ž 또는 읞슀턎슀 잡멎의 유형읎얎알 하는지 여부에 대한 토론곌 ꎀ렚하여 또 닀륞 아읎디얎가 있었습니닀. this 는 정적 잡멎읎 될 수 있윌며 읞슀턎슀 멀버에서 수행되는 작업곌 런타임 동작읎 음치하멎 this.prototype 륌 통핎 읞슀턎슀 유형을 얻을 수 있습니닀.

abstract class Model {
  static findAll(): Promise<this.prototype[]>
}

class User extends Model {}

const users: User[] = await User.findAll();

읎것은 JavaScript에서 작동하는 방식곌 음치합니닀. this 는 큎래슀 개첎 자첎읎고 읞슀턎슀는 this.prototype 에 있습니닀. this['prototype'] 에 핎당하는 맀핑된 유형곌 볞질적윌로 동음한 메컀니슘입니닀.

같은 방식윌로 this.constructor 륌 통핎 읞슀턎슀 멀버에서 정적 잡멎을 사용할 수 있닀고 상상할 수 있습니닀(읎 atm의 사용 사례는 생각할 수 없습니닀).

또한 얞꞉된 í•Žê²° 방법/핵심 쀑 얎느 것도 Sequelize에서 ORM 몚덞을 입력하는 데 작동하지 않는닀는 점을 얞꞉하고 싶었습니닀.

  • this 유형 죌석은 생성자에서 사용할 수 없윌므로 읎 서명에서는 작동하지 않습니닀.
    ts abstract class Model { constructor(values: Partial<this.prototype>) }
  • 정적 멀버는 음반 맀개 변수륌 ì°žì¡°í•  수 없윌므로 형식을 음반 큎래슀 읞수로 전달하멎 정적 메서드에서 작동하지 않습니닀.
  • 형식을 음반 메서드 읞수로 전달하멎 메서드에서는 작동하지만 닀음곌 같은 정적 속성에서는 작동하지 않습니닀.
    ts abstract class Model { static attributes: { [K in keyof this.prototype]: { type: DataType, field: string, unique: boolean, primaryKey: boolean, autoIncrement: boolean } }; }

읎 요청에 대핮 +1입니닀. 낮 ORM은 훚씬 깚끗합니닀.

곧 깚끗한 솔룚션을 볌 수 있Ʞ륌 바랍니닀.

한펾, 솔룚션을 제공한 몚든 분듀께 감사드늜니닀!

더 읎상 녌의가 없Ʞ 때묞에 더 진행핎도 될까요?

얎디로 가젞가시겠습니까? 읎것은 ë‚Žê°€ 아는 한 Typescript가 Javascript륌 깔끔하게 몚덞링할 수 없고 닚순히 수행하지 않는 것 왞에 í•Žê²° 방법을 볞 적읎 없는 방식입니닀.

읎믞 ì„ž 명의 읞Ʞ 있는 ORM 소유자가 읎 Ʞ능을 요청한 것을 볌 수 있윌므로 읎것은 ORM 개발자에게 필수 Ʞ능입니닀.

@pleerock @xealot 솔룚션은 위에서 제안되었습니닀.

export type StaticThis<T> = { new (): T };

export class Base {
    static create<T extends Base>(this: StaticThis<T>) {
        const that = new this();
        return that;
    }
    baseMethod() { }
}

export class Derived extends Base {
    derivedMethod() { }
}

// works
Base.create().baseMethod();
Derived.create().baseMethod();
// works too
Derived.create().derivedMethod();
// does not work (normal)
Base.create().derivedMethod();

나는 읎것을 ꎑ범위하게 사용하고 있습니닀. Ʞ볞 큎래슀의 정적 메서드 선얞은 앜간 묎겁지만 정적 메서드 낮 this 유형의 왜곡을 플하Ʞ 위핎 지불핎알 하는 대가입니닀.

@pleerock

this: 팚턎을 묞제 없읎 ꎑ범위하게 사용하는 사낎 ORM읎 있습니닀.

Ʞ능읎 싀제로 읎믞 여Ʞ에 있는 겜우 얞얎륌 곌도하게 청구할 필요가 없닀고 생각합니닀. 볎닀 명확한 구묞에 대한 사용 사례는 맀우 제한적읎며 불음치륌 유발할 수 있습니닀.

읎 질묞곌 ì°žì¡°ìš© 솔룚션읎 있는 Stackoverflow 슀레드가 있을 수 있습니까?

@bjouhier @ceymard 읎 슀레드의 몚든 í•Žê²° 방법읎 Sequelize에서 작동하지 않는 읎유륌 섀명했습니닀. https://github.com/Microsoft/TypeScript/issues/5863#issuecomment -269463313

귞늬고 읎것은 ORM뿐만 아니띌 표쀀 띌읎람러늬에 ꎀ한 것입니닀. https://github.com/Microsoft/TypeScript/issues/5863#issuecomment -244550725

@felixfbecker 방ꞈ 생성자 사용 사례에 대핮 게시하고 삭제했습니닀(게시 직후 TS가 몚든 하위 큎래슀에서 생성자륌 의묎화하지 않는닀는 것을 깚달았습니닀).

@felixbecker 생성자의 겜우 맀개변수가 없는 생성자륌 고수하고 대신 특수 정적 메서드(create, clone, ...)륌 제공하여 핎결합니닀. 더 명확하고 입력하Ʞ 쉜습니닀.

@bjouhier 슉, Ʞ볞적윌로 몚든 몚덞 하위 큎래슀에서 몚든 닚음 메서드륌 닀시 ì„ ì–ží•Žì•Œ 합니닀. Sequelize에 얌마나 많은지 볎십시였: http://docs.sequelizejs.com/class/lib/model.js~Model.html

낮 죌장은 완전히 닀륞 ꎀ점에서 나옚 것입니닀. 부분적읎고 닀소 직ꎀ적읎지 않은 í•Žê²° 방법읎 있윌며 읎것읎 충분한지 여부에 대핮 녌쟁하고 동의하지 않을 수 있지만 읎것읎 Typescript가 Javascript륌 쉜게 몚덞링할 수 없는 영역읎띌는 데 동의할 수 있습니닀.

귞늬고 낮 읎핎는 Typescript가 Javascript의 확장읎얎알 한닀는 것입니닀.

@felixfbecker

읎는 Ʞ볞적윌로 몚든 몚덞 하위 큎래슀에서 몚든 닚음 메서드륌 닀시 ì„ ì–ží•Žì•Œ 핚을 의믞합니닀.

왜요? 귞것은 전혀 낮 겜험읎 아닙니닀. 윔드 샘플로 묞제륌 섀명할 수 있습니까?

@bjouhier 나는 읎 슀레드의 낮 죌석에 있는 윔드 샘플로 묞제륌 심도 있게 섀명했습니닀. 시작을 위핎 https://github.com/Microsoft/TypeScript/issues/5863#issuecomment -222348054

하지만 위의 create 예제륌 볎십시였. create 메서드는 정적 메서드입니닀. 닀시 선얞되지 않았지만 하위 큎래슀에 제대로 입력되었습니닀. 귞렇닀멎 Model 의 메소드에 재정의가 필요한 읎유는 묎엇입니까?

@felixfbecker 귀하의 _시작을 위한_ 예:

export type StaticThis<T> = { new (): T };

abstract class Model {
    public static tableName: string;
    public static findById<T extends Model>(this: StaticThis<T>, id: number): T {
        const instance = new this();
        // details omitted
        return instance;        
    }
}

class User extends Model {
    public static tableName = 'users';
    public username: string;
}

const user = User.findById(1); 
console.log(user.username);

@bjouhier 좋아, this: { new (): T } 죌석읎 싀제로 유형 추론읎 작동하는 것처럌 볎입니닀. 읎것읎 컎파음러가 사용하는 Ʞ볞 유형읎 아닌 읎유가 궁ꞈ합니닀.
this 맀개변수륌 가질 수 없Ʞ 때묞에 í•Žê²° 방법은 묌론 생성자에 대핮 작동하지 않습니닀.

예, 생성자에서는 작동하지 않지만 정적 create 메서드륌 추가하여 작은 API 변겜윌로 묞제륌 í•Žê²°í•  수 있습니닀.

읎핎하지만 읎것은 JavaScript 띌읎람러늬읎므로 선얞에 êž°ì¡Ž API륌 입력하는 것에 대핮 읎알Ʞ하고 있습니닀.

this 가 정적 메서드 낎에서 { new (): T } $륌 의믞한닀멎 this 는 정적 메서드 낎에서 this 에 대한 올바륞 유형읎 아닙니닀. 예륌 듀얎 new this() 는 허용되지 않습니닀. 음ꎀ성을 위핎 this 는 큎래슀 읞슀턎슀의 유형읎 아니띌 생성자 핚수의 유형읎얎알 합니닀.

êž°ì¡Ž 띌읎람러늬륌 입력하는 데 묞제가 있습니닀. 핎당 띌읎람러늬륌 제얎할 수 없는 겜우 적절한 형식의 create 핚수륌 사용하여 쀑간 Ʞ볞 큎래슀( BaseModel extends Model )륌 만듀고 BaseModel 에서 몚든 몚덞을 파생시킬 수 있습니닀.

Ʞ볞 큎래슀의 정적 속성에 액섞슀하렀멎 닀음을 사용할 수 있습니닀.

public static findById<T extends Model>(this: (new () => T) & typeof Model, id: number): T {...}

귞러나 아마도 생성자에 대한 유횚한 요점읎 있을 것입니닀. 컎파음러가 닀음을 거부핎알 하는 얎렀욎 읎유륌 찟지 못했습니닀.

constructor(values: Partial<this>) {}

나는 여Ʞ에 고통읎 있닀는 @xealot 에 동의합니닀. 우늬가 ì“ž 수 있닀멎 너묎 멋질 것입니닀.

static findById(id: number): instanceof this { ... }

대신에

static findById<T extends Model>(this: (new () => T), id: number): T { ... }

귞러나 우늬는 타읎핑 시슀템에서 새로욎 연산자가 필요합니닀( instanceof ?). 닀음은 유횚하지 않습니닀.

static findById(id: number): this { ... }

TS 2.4는 닀음 í•Žê²° 방법을 쀑닚했습니닀.
https://travis-ci.org/types/sequelize/builds/247636686

@sandersn @felixfbecker 나는 읎것읎 유횚한 버귞띌고 생각합니닀. 귞러나 최소한의 방식윌로는 재현할 수 없습니닀. 윜백 맀개변수는 반공변입니닀.

// Hooks
User.afterFind((users: User[], options: FindOptions) => {
  console.log('found');
});

읎 묞제가 얞젠가는 핎결될 가능성읎 있습니까?

나는 였늘도 읎것에 부딪쳀닀. Ʞ볞적윌로 닀음곌 같읎 싱Ꞁ톀 Ʞ볞 큎래슀륌 만듀고 싶었습니닀.

abstract class Singleton<T> {
  private static _instance?: T

  public static function getInstance (): T {
    return this._instance || (this._instance = new T())
  }
}

사용법은 닀음곌 같습니닀.

class Foo extends Singleton<Foo> {
  bar () {
    console.log('baz!')
  }
}

Foo.getInstance().bar() // baz!

위에서 얞꞉한 StaticThis 변형곌 닀륞 많은 변형을 포핚하여 읎것의 ì•œ 10가지 변형을 시도했습니닀. ê²°êµ­ 컎파음되는 버전은 하나뿐읎지만 getInstance() 의 결곌는 getInstance() Object 파생되었습니닀.

나는 읎것읎 읎러한 구성윌로 작업하는 것볎닀 훚씬 얎렵닀고 생각합니닀.

닀음 작품:

class Singleton {
    private static _instance?: Singleton;

    static getInstance<T extends Singleton>(this: { new(): T }) {
      const constr = this as any as typeof Singleton; // hack
      return (constr._instance || (constr._instance = new this())) as T;
    }
  }

  class Foo extends Singleton {
    foo () { console.log('foo!'); }
  }

  class Bar extends Singleton {
    bar () { console.log('bar!');}
  }

  Foo.getInstance().foo();
  Bar.getInstance().bar();

this as any as typeof Singleton 부분은 볎Ʞ 흉하지만 _instance 가 파생 큎래슀의 생성자에 저장되얎알 하므로 유형 시슀템을 속읎고 있음을 나타냅니닀.

음반적윌로 Ʞ볞 큎래슀는 프레임워크에 묻히므로 구현읎 앜간 못생ꞎ 겜우에도 크게 핎륌 끌치지 않습니닀. 쀑요한 것은 파생 큎래슀의 깚끗한 윔드입니닀.

2.8 nightlies에서 닀음곌 같읎 할 수 있Ʞ륌 바랐습니닀.

static findById(id: number): InstanceType<this> { ... }

슬프게도 귞런 행욎은 없습니닀 :(

@bjouhier 윔드 예제는 맀력처럌 작동합니닀. 귞러나 IntelliSense 자동 완성을 쀑닚합니닀.

React 16.3.0읎 출시되었윌며 정적 메소드가 큎래슀 유형 맀개변수륌 ì°žì¡°í•  수 없는 겜우 새로욎 getDerivedStateFromProps 메소드륌 올바륎게 입력하는 것읎 불가능핎 볎입니닀.

(닚순한 예)

class Component<P, S> {

    static getDerivedStateFromProps?<K extends keyof S>(nextProps: P, prevState: S): Pick<S, K> | null

    props: P
    state: S
}

í•Žê²° 방법읎 있습니까? (나는 "P와 S륌 PP와 SS로 입력하고 개발자듀읎 읎 두 유형 팚밀늬륌 정확하게 음치시킀Ꞟ 바랍니닀"륌 하나로 계산하지 않습니닀.)

홍볎: https://github.com/DefinitelyTyped/DefinitelyTyped/pull/24577

@cncolder 나도 Intellisense의 파ꎎ륌 목격했습니닀. 나는 귞것읎 typescript 2.7에서 시작되었닀고 믿습니닀.

여Ʞ에서 볌 수 없는 한 가지는 Singleton 예제륌 확장하는 것입니닀. Singleton / Multiton 큎래슀에 볎혞된 생성자륌 만드는 것읎 음반적읞 팚턎입니닀. 귞늬고 유형읎 { new(): T } 읞 겜우 확장할 수 없습니닀. 공개 생성자륌 적용합니닀 - this ìš©ì–Ž 또는 여Ʞ에 제공된 닀륞 솔룚션( instanceof this , typeof this 등)읎 핎당 묞제륌 í•Žê²°í•Žì•Œ 합니닀. 읎것은 싱Ꞁ톀읎 생성 등을 요청하지 않은 겜우 생성자에서 였류륌 던지멎 확싀히 가능합니닀. 귞러나 읎는 였류 입력의 목적을 묎횚화합니닀 - 런타임 솔룚션을 ê°–êž° 위핎...

class Singleton {

  private static _instance?: Singleton;

  public static getInstance<T extends Singleton> ( this: { new(): T } ): T {
    const ctor: typeof Singleton = this as any; // hack
    return (ctor._instance || (ctor._instance = new this())) as T;
  }

  protected constructor ( ) { return; } 
}

class A extends Singleton {
  protected constructor ( ) {
    super();
  }
}

A.getInstance() // fails because constructor is not public

getInstance() 가 있는 TS에서 싱Ꞁ톀읎 필요한 읎유륌 몚륎겠습니닀. 개첎 늬터럎을 정의하멎 됩니닀. 또는 절대적윌로 큎래슀륌 사용하렀는 겜우(비공개 멀버의 겜우) 큎래슀 읞슀턎슀만 낎볎낎고 큎래슀는 낎볎낎지 않거나 큎래슀 표현식( export new class ... )을 사용합니닀.

읎것은 Multiton에 더 유용합니닀. 귞늬고 저는 작동하는 팚턎을 발견했닀고 믿습니닀. 비록 읎 유형읎 없윌멎 여전히 맀우 핎킀한 느낌읎지만.. 대신 읎것은 필요합니닀.

this -> { new(): T } & typeof Multiton | Function

class Multiton {
  private static _instances?: { [key: string]: any };

  public static getInstance<T extends Multiton> (
    this: { new(): T } & typeof Multiton | Function, key: string
  ): T {
    const instances: { [key: string]: T } =
      (this as typeof Multiton)._instances ||
     ((this as typeof Multiton)._instances = { });

    return (instances[key] ||
      (instances[key] = new (this as typeof Multiton)() as T)
    );
  }

  protected constructor ( ) { return; }
}

class A extends Multiton {
  public getA ( ): void { return; }
}
A.getInstance("some-key").getA();
assert(A.getInstance("some-key") === A.getInstance("some-key"))
new A(); // type error, protected constructor

또한 생성 시 자식 큎래슀에서 액섞슀할 수 있도록 킀륌 저장하는 윔드가 있지만 닚순성을 위핎 제거했습니닀...

안녕. 생성자에 대핮 닀형성 "this"가 필요한 묞제가 발생했습니닀. 읎 댓Ꞁ곌 비슷합니닀.

수업을 만듀고 싶습니닀. 큎래슀 자첎에는 많은 속성읎 있윌므로 핎당 큎래슀의 몚든 속성읎 생성자의 맀개변수륌 통핎 쎈Ʞ화되멎 생성자가 볎Ʞ에 좋지 않습니닀.

속성을 쎈Ʞ화하Ʞ 위핎 개첎륌 허용하는 생성자륌 선혞합니닀. 예륌 듀얎:

class Vehicle {
  // many properties here
  // ...

  constructor(value: Partial<Vehicle>) {
      Object.assign(this, value)
  }
}

let vehicle = new Vehicle({
  // <-- IntelliSense works here
})

귞런 닀음 수업을 연장하고 싶습니닀. 예륌 듀얎:

class Car extends Vehicle {
  // more properties here
  // ...
}

let car = new Car({
  // <-- I can't infer Car's properties here
})

this 유형을 생성자에서도 사용할 수 있닀멎 맀우 좋을 것입니닀.

class Vehicle {
  // ...
  constructor(value: Partial<this>) {
      // ...

따띌서 IntelliSense는 추가 상용구 없읎 자식 큎래슀의 속성을 유추할 수 있습니닀(예: 생성자 재정의). 큎래슀 쎈Ʞ화륌 위핎 정적 메서드륌 사용하는 것볎닀 더 자연슀럜게 볎음 것입니닀.

let car = new Car({
  // <-- Car's properties will be able to be inferred if Partial<this> is allowed
})

고렀핎죌셔서 대당히 감사합니닀.

읎 슀레드륌 발견하게 되얎 Ʞ쁩니닀. 나는 솔직히 읎것읎 맀우 심각한 묞제띌고 생각하며 3.0까지 읎얎지는 것을 볎고 맀우 낙닎했습니닀.

몚든 솔룚션을 삎펎볎고 지난 몇 년 동안 수행한 닀양한 í•Žê²° 방법을 고렀하멎 솔룚션읎 쀀비되얎 있윌멎 빠륞 수정 읎 싀팚할 것읎띌는 결론에 도달했습니닀. 귞때까지 우늬가 하는 몚든 강제는 프로젝튞 전첎에서 유지하Ʞ 위핎 너묎 많은 수작업을 필요로 합니닀. 귞늬고 음닚 게시되멎 소비자가 자신의 사고 방식을 읎핎하고 TypeScript륌 수정하Ʞ로 선택한 읎유륌 소비자가 닚순히 바닐띌로 팚킀지륌 소비하지만 우늬 대부분곌 마찬가지로 VSCode륌 사용하는 겜우에 읎핎할 수 없습니닀.

동시에 싀제 ì–žì–Žê°€ 묞제가 아닐 때 Type System을 만족슀럜게 만드는 윔드륌 작성하는 것은 Typed Ʞ능을 사용하는 것곌 동음한 읎유로 시작됩니닀.

몚든 사람에게 ë‚Žê°€ 추천하는 것은 구불구불한 몚양읎 잘못 되었닀는 것을 받아듀읎고 가능한 겜우 //@ts-ignore because my code works as expected 륌 사용하는 것입니닀.

당신의 늰터가 합늬적읞 읞간 지능에 멎역읎 있닀멎, ê·ž 자늬륌 알고 있는 늰터륌 ì°Ÿì•„ì•Œ 할 때입니닀.

업데읎튞 :
정적 추론 을 안전하게 강화하Ʞ 위핎 낮 자신의 시도륌 추가하고 싶었습니닀. 읎 ì ‘ê·Œ 방식은 ë°©í•Žê°€ 되지 않도록 하Ʞ 위핎 엄격하게 죌변적입니닀. 상속읎 당신을 위핎 음할 것읎띌고 가정하지 않고 당신의 슝강을 확읞하도록 강요하는 것은 철저하게 명시적입니닀.

export class Sequence<T> {
  static from(...values) {
    // 
 returns Sequence<T>
  };
}

export class Peekable<T> extends Sequence<T> {
  // no augmentations needed in actual class body
}

/// AMBIENT /// Usually keep those at the bottom of my files

export declare namespace Peekable {
  export function from<T>(... values: T[]): Peekable<T>;
}

분명히 읎 팚턎읎 유지되거나 읎 슀레드의 몚든 시나늬였륌 충족한닀고 볎장할 수 없지만 현재로서는 예상대로 작동합니닀.

읎러한 선택은 읎 시점까지 TypeScript의 자첎 lib 파음에 두 개의 큎래슀 선얞만 포핚된닀는 읞식에서 비롯되었습니닀!

섞읎프얎레읎

/**
 * Represents an Automation SAFEARRAY
 */
declare class SafeArray<T = any> {
    private constructor();
    private SafeArray_typekey: SafeArray<T>;
}

변수 날짜

/**
 * Automation date (VT_DATE)
 */
declare class VarDate {
    private constructor();
    private VarDate_typekey: VarDate;
}

였늘은 잠시 토론했습니닀. í‚€ 포읞튞:

  • this 는 읞슀턎슀 쪜을 찞조합니까 아니멎 정적 쪜을 찞조합니까?

    • 확싀히 정적 ìž¡ë©Ž. 읞슀턎슀 쪜은 InstanceTypeOf 륌 통핎 ì°žì¡°í•  수 있지만 ê·ž 반대는 사싀읎 아닙니닀. 읎것은 또한 서명의 this this 와 동음한 유형을 갖도록 대칭을 유지합니닀.

  • 걎전성 묞제

    • 파생 큎래슀 생성자 맀개변수 목록읎 Ʞ볞 큎래슀 생성자 맀개변수 목록곌 ꎀ렚읎 있닀는 볎장은 없습니닀.

    • 큎래슀는 읎와 ꎀ렚하여 맀우 자죌 정적 ìž¡ 대첎 가능성을 깚뜚늜니닀.

    • 비구성잡 대첎 가능성 읎 시행되며 읎것은 음반적윌로 사람듀읎 얎욌든 ꎀ심을 갖는 것입니닀.

    • 우늬는 읎믞 static new this() 의 불걎전한 혞출을 허용합니닀.

    • 아묎도 왞부에서 정적 this 의 구성 서명 잡멎에 대핮 신겜 쓰지 않을 것입니까?

êž°ì¡Ž í•Žê²° 방법:

class Foo {
    static boo<T extends typeof Foo>(this: T): InstanceType<T> {
        return (new this()) as InstanceType<T>;
    }
}

class Bar extends Foo {
}

// b: Bar
let b = Bar.boo();

특히 읎것은 Bar 의 구성 서명읎 Foo 륌 적절히 대첎할 수 있는 겜우에만 작동합니닀.

@RyanCavanaugh this 에 대한 값읎 귀하의 예제 static boo<T extends typeof Foo>(this: T): InstanceType<T> 에서 유래한 섀명을 제시하렀고 했지만 읎핎가 되지 않습니닀. 제넀늭에 대한 몚든 것을 닀시 읜었지만 여전히 - 아니요. 예륌 듀얎 this 륌 clazz 로 바꟞멎 더 읎상 작동하지 않고 컎파음러는 "읞수 1개륌 예상했지만 0을 얻었습니닀."띌고 불평합니닀. 귞래서 마법읎 음얎나고 있습니닀. 섀명핎 죌시겠습니까? 아니멎 묞서의 올바륞 방향을 알렀죌시겠습니까?

펞집하닀:
또한 닚순히 extends Foo 가 아닌 extends typeof Foo 읞 읎유는 묎엇입니까?

@creynders this 는 핚수의 컚텍슀튞에 대핮 입력할 수 있는 특수한 가짜 맀개변수입니닀. 묞서 .

제넀늭읎 ꎀ렚된 겜우 InstanceType<T> 륌 사용하멎 작동하지 않습니닀.

낮 사용 사례는 닀음곌 같습니닀.

const _data = Symbol('data');

class ModelBase<T> {
    [_data]: Readonly<T>;

    protected constructor(data: T) {
        this[_data] = Object.freeze(data);
    }


    static create<T, V extends typeof ModelBase>(this: V, data : T): InstanceType<V> {
        return new this(data);
    }
}

interface IUserData {
    id: number;
}

class User extends ModelBase<IUserData> {}

User.create({ id: 5 });

TypeScript 플레읎귞띌욎드 링크

@mastermatt 였 와우, 묞서륌 읜을 때 완전히 선택하지 않았습니닀... 감사합니닀.

@RyanCavanaugh 의 예륌 볎멎 정적 메서드가 작동하도록 할 수 있었지만 정적 메서드륌 찞조하는 읞슀턎슀 메서드도 있지만 올바륞 입력 방법을 알 수 없습니닀.

예시:

class Foo {
    static boo<T extends typeof Foo>(this: T): InstanceType<T> {
        return (new this()) as InstanceType<T>;
    }

    boo<T extends typeof Foo>(this: InstanceType<T>): InstanceType<T> {
      return (this.constructor as T).boo();
    }
}

class Bar extends Foo {
}

// b: Bar
let b = Bar.boo();
// c: Foo
let c = b.boo();

읎 마지막 묞제에 대한 í•Žê²° 방법을 찟을 수 있닀멎 공식적읞 묎얞가가 나올 때까지 섀정하겠습니닀.

또한 핎당 예에서 하위 큎래슀가 정적 메서드륌 재정의한 닀음 super 륌 혞출하렀고 하멎 몚두 화가 납니닀... 읎 두 가지 묞제 왞에 í•Žê²° 방법은 제대로 작동하는 것 같습니닀. 하지만 읎 두 가지 묞제가 우늬 윔드륌 찚닚하고 있습니닀.

IIRC 읎것은 타입 시슀템을 앜간 구부늬지 않고는 타읎프슀크늜튞로 표현할 수 없Ʞ 때묞입니닀. 에서와 같읎 ; this.constructor는 당신읎 생각하는 것읎나 귞와 비슷한 것읎 전혀 볎장되지 않습니닀.

읎 정확한 겜우에는 boo() 읞슀턎슀 메서드가 this 륌 반환하고 낎부에서 앜간의 속임수륌 사용하여 컎파음러가 ë‚Žê°€ 묎엇을 하고 있는지 알고 있음을 읞정하도록 합니닀.

낮 음반적읞 추론은 때때로 앜간의 속임수륌 의믞하더띌도 나뚞지 윔드에 대핮 API가 가능한 한 닚순하Ʞ륌 원한닀는 것입니닀.

누군가 더 강력한 것을 가지고 있닀멎 나는 귞것을 좋아할 것입니닀.

class Foo {
  static boo<T extends typeof Foo>(this: T): InstanceType<T> {
      return (new this()) as InstanceType<T>;
  }

  boo(): this {
    // @ts-ignore : wow this is ugly 
    return (this.constructor).boo();
  }
}

class Bar extends Foo {
}

// b: Bar
let b = Bar.boo();
// c: Bar !
let c = b.boo();

읞터페읎슀 겜로로 읎동하여 읎와 같은 작업을 수행할 수도 있습니닀.

interface FooMaker<T> {
  new(...a: any[]): T
  boo(): T
}


class Foo {
  static boo<T extends typeof Foo>(this: T): InstanceType<T> {
      return (new this()) as InstanceType<T>;
  }

  boo(): this {
    return (this.constructor as FooMaker<this>).boo();
  }
}

class Bar extends Foo {
}

// b: Bar
let b = Bar.boo();
// c: Bar !
let c = b.boo();

읎것도 부정 행위읎지만 조ꞈ 더 통제가 가능합니까? 정말 말할 수 없습니닀.

귞래서 정적 "boo" 메소드의 첫 번짞, this 읞수는 음반 읞수가 아닌 특별히 처늬됩니까? 읎것을 섀명하는 묞서에 대한 링크가 있습니까?

class Foo {
    static boo<T extends typeof Foo>(this: T): InstanceType<T> {
        return (new this()) as InstanceType<T>;
    }
}

class Bar extends Foo {
}

// b: Bar
let b = Bar.boo();

나는 같은 (적얎도 비슷한) 묞제가 있습니닀.
저는 JSDoc(TypeScript가 아님)와 핚께 Vanilla Javascript륌 사용하고 있윌므로 읎 슀레드에서 제안된 제넀늭을 쀑심윌로 회전하는 í•Žê²° 방법을 사용/구현할 수 없지만 룚튞는 동음한 것 같습니닀.
읎 묞제륌 엎었습니닀. #28880

읎 묞제는 말 귞대로 읎믞 3년읎 지났습니닀.
나에게 맞는 적절한 í•Žê²° 방법을 찟은 사람읎 있습니까?

ì‚Œ 년

@RyanCavanaugh 의 í•Žê²° 방법은 정적 메서드에 적합하지만 정적 접귌자는 얎떻습니까?

class Factory<T> {
  get(): T { ... }
}

class Base {
  static factory<T extends Base>(this: Constructor<T>): Factory<T> {
    //
  }

  // what about a getter?
  static get factory<** no generics allowed for accessors **> ...
}

ì‚Œ 년

좋아, 당신은 날짜륌 빌는 데 절반 정도는 ꎜ찮습니닀. 하지만 핎결책을 제시할 수 있습니까? ;)

@RyanCavanaugh 읎것은 닀음곌 같읎 제너레읎터에서 this 값을 사용할 때 묞제입니닀.

class C {
  constructor(f: (this: this) => void) {
  }
}
new C(function* () {
  this;
  yield;
});

생성Ʞ륌 만듀 때 화삎표 핚수륌 사용하여 this 값을 사용할 수 없습니닀. 읎제 우늬는 서람큎래슀에서 명시적윌로 this 유형을 ì„ ì–ží•Žì•Œ 합니닀. 싀제 사례는 닀음곌 같습니닀.

      class Component extends Coroutine<void> implements El {
        constructor() {
          super(function* (this: Component) {
            while (true) {
              yield;
            }
          }, { size: Infinity });
        }
        private readonly dom = Shadow.section({
          style: HTML.style(`ul { width: 100px; }`),
          content: HTML.ul([
            HTML.li(`item`)
          ] as const),
        });
        public readonly element = this.dom.element;
        public get children() {
          return this.dom.children.content.children;
        }
        public set children(children) {
          this.dom.children.content.children = children;
        }
      }

https://github.com/falsandtru/typed-dom/blob/v0.0.134/test/integration/package.ts#L469

Ʞ볞 큎래슀에서 할 수 있닀멎 서람큎래슀에서 this 유형을 ì„ ì–ží•  필요가 없습니닀. 당, 슈퍌 큎래슀에서 제너레읎터가 동Ʞ적윌로 혞출될 때 this 값은 쎈Ʞ화되지 않는닀. 윔드에서 읎 묞제륌 플했지만 읎것은 더러욎 핎킹입니닀. 따띌서 읎 팚턎은 원래 큎래슀 êž°ë°˜ 프로귞래밍 얞얎와 음치하지 않을 수 있습니닀.

가장 깚끗하지는 않지만 정적 메서드에서 자식 큎래슀에 액섞슀하는 데 유용할 수 있습니닀.

class Base {
    static foo<T extends typeof Base>() {
        let ctr = Object.create(this.prototype as InstanceType<T>).constructor;
        // ...
    }
}

class C extends Base {
}

C.foo();

현재 제가 겪고 있는 묞제가 읎것 때묞읞지는 몚륎겠지만 읎 묞제륌 간닚히 삎펎볎멎 아마도 귞럎 것 같습니닀. 귞렇지 않은 겜우 수정하십시였.

귞래서 상속을 통핎 ꎀ렚된 닀음 2개의 큎래슀가 있습니닀.

export class Target {
  public static create<T extends Target = Target>(that: Partial<T>): T {
    const obj: T = Object.create(this.prototype);
    this.mapObject(obj, that);
    return obj;
  }
  public static mapObject<T extends Target = Target>(obj: T, that: Partial<T>) {
    // works with "strictNullChecks": false
    obj.prop1 = that.prop1;
    obj.prop2 = that.prop2;
  }

  public prop1!: string;
  constructor(public prop2: string) {}
}

export class SubTarget extends Target {
  public subProp!: string;
}

닀음윌로 SubTarget 큎래슀에 mapObject 메소드륌 닀음곌 같읎 추가합니닀.

  public static mapObject(obj: SubTarget, that: Partial<SubTarget>) {
    super.mapObject(obj, that);
    obj.subProp = that.subProp;
  }

읎것읎 작동할 것윌로 예상했지만 닀음 였류가 발생합니닀.

Class static side 'typeof SubTarget' incorrectly extends base class static side 'typeof Target'.
  Types of property 'mapObject' are incompatible.
    Type '(obj: SubTarget, that: Partial<SubTarget>) => void' is not assignable to type '<T extends Target>(obj: T, that: Partial<T>) => void'.
      Types of parameters 'obj' and 'obj' are incompatible.
        Type 'T' is not assignable to type 'SubTarget'.
          Property 'subProp' is missing in type 'Target' but required in type 'SubTarget'.

읎 묞제로 읞핎 읎 였류가 발생합니까? 귞렇지 않윌멎 섀명읎 정말 좋을 것입니닀.

놀읎터 바로가Ʞ

혞출되는 싀제 큎래슀의 새 읞슀턎슀륌 반환하는 정적 메서드에 죌석을 달Ʞ 위한 솔룚션을 찟는 동안 여Ʞ에 왔습니닀.

@SMotaal 읎 제안한 í•Žê²° 방법( new this() 와 핚께 사용)읎 가장 깚끗하고 나에게 가장 합늬적읎띌고 생각합니닀. 원하는 의도륌 표현할 수 있고 제넀늭 메서드륌 혞출할 때마닀 유형을 지정하지 않아도 되며 최종 윔드에 였버헀드가 추가되지 않습니닀.

귞러나 진지하게 읎것읎 아직 핵심 Typescript의 음부가 아닌 읎유는 묎엇입니까? 상당히 음반적읞 시나늬였입니닀.

@danielvy — OOP와 프로토타입 사읎의 닚절읎 몚두륌 행복하게 하지 못하는 더 큰 정신적 격찚띌고 생각합니닀. 낮 생각에 큎래슀에 대한 핵심 가정은 사양에서 진화한 큎래슀 Ʞ능읎 정렬되지 않았고, 읎륌 깚는 것은 많은 TypeScript Ʞ능에 대한 핚정읎므로 몚든 사람읎 "우선 순위륌 지정"하고 있윌며 ꎜ찮지만 " 유형"읎띌고 생각합니닀. 겜쟁 제품볎닀 더 나은 솔룚션읎 없는 것은 겜쟁읎 있는 겜우에만 묞제입니닀. 읎것읎 순전히 한 바구니에 닎ꞎ 몚든 계란읎 항상 몚두에게 나쁜 읎유입니닀. 저는 싀용적읎고 성싀합니닀.

읎것은 작동하지 않습니닀:

export class Base {
  static getEntitySchema<T extends typeof Base>(
    this: T,
  ): InstanceType<T> {
  }
}

export class Extension extends Base {
  static member: string = '';
  static getEntitySchema<T extends typeof Extension>(
    this: T,
  ): InstanceType<T> {
  }
}

Type 'typeof Base' is missing the following properties from type 'typeof Extension ': member.

귞러나 Extension읎 Base륌 확장하므로 읎것읎 허용되얎서는 안됩니까?

읎것읎 작동한닀는 점에 유의하십시였.

export class Extension extends Base {
  static member: string = '';
  static getEntitySchema<T extends typeof Base>(
    this: T,
  ): InstanceType<T> {
  }
}

하지만 ê·ž 안에 this.member륌 사용할 수 없습니닀.

귞래서 @ntucker 게시묌에서 확장 큎래슀가 Ʞ볞 큎래슀와 정확히 음치하지 않는 한 í•Žê²° 방법은 한 수쀀 깊읎에서만 작동한닀고 추잡하고 있습니닀.

여볎섞요! 볎혞된 생성자는 얎떻습니까?

class A {
  static create<T extends A>(
    this: {new(): T}
  ) {
    return new this();
  }

  protected constructor() {}
}

class B extends A {} 

B.create(); // Error ts(2684)

생성자가 public 읎멎 ꎜ찮지만 귞렇지 않윌멎 였류가 발생합니닀.

The 'this' context of type 'typeof B' is not assignable to method's 'this' of type '(new () => B) & typeof A'.
  Type 'typeof B' is not assignable to type 'new () => B'.
    Cannot assign a 'protected' constructor type to a 'public' constructor type.

놀읎터 - http://tiny.cc/r74c9y

읎에 대한 희망읎 있습니까? 읎 필요륌 닀시 한 번 우연히 발견했습니닀 :F

@ntucker Duuuuudee 수고하셚습니닀!!! 저에게 쀑요한 깚달음은 this 맀개변수륌 선얞하고 마지막에 InstanceType<U> 캐슀튞륌 수행하여 정적 create 메소드륌 음반화하는 것읎었습니닀.

욎동장

위에서 ^

class Base<T> {
  public static create<U extends typeof Base>(
    this: U
  ) {
    return new this() as InstanceType<U>
  }
}
class Derived extends Base<Derived> {}
const d: Derived = Derived.create() // works 😄 

읎것은 낮 사용 사례륌 완벜하게 충족시킀며 TS 3.5.1 현재 읎 슀레드의 ppl 대부분을 만족시킀는 것 같습니닀(정적 소품 theAnswer 및 3닚계 확장 탐색을 위한 놀읎터 ì°žì¡°)

핫 테읎크: 읎것읎 지ꞈ 작동하고 닫을 수 있닀고 생각합니까?

@jonjaques Btw 당신은 T륌 절대 사용하지 않습니닀. 또한 읎것은 메서드륌 재정의하는 ë‚Žê°€ 섀명한 묞제륌 핎결하지 못합니닀.

얞꞉한 솔룚션은 읎믞 거의 4년 전에 제안된 것 같습니닀. 하지만 아직 묞제륌 핎결하는 것은 아닙니닀.

누군가가 알고 있을 수 있는 닀륞 í•Žê²° 방법읎 있고 누군가 ë‚Žê°€ 겪고 있는 묞제에 대한 좋은 요앜읎 있는지 확읞하Ʞ 위핎 stackoverflow 륌 엎었습니닀.

"읎 맀개변수륌 포핚하여 메서드 맀개변수로 사용되는 제넀늭은 반공변읞 것 같지만 싀제로는 항상 읎 맀개변수가 공변(또는 심지얎 읎변)윌로 처늬되Ʞ륌 원합니닀."

따띌서 읎것은 싀제로 TypeScript 자첎에서 손상되얎 수정되얎알 하는 것 같습니닀('this'는 공변 또는 읎변읎얎알 핹).

펞집: 읎 의견에는 더 나은 방법읎 있습니닀.

추가할 낎용읎 많지는 않지만 https://github.com/microsoft/TypeScript/issues/5863#issuecomment -437217433 에서 잘 작동했습니닀.

class Foo {
    static create<T extends typeof Foo>(this: T): InstanceType<T> {
        return (new this()) as InstanceType<T>;
    }
}

class Bar extends Foo { }

// typeof b is Bar.
const b = Bar.create()

읎 ꞎ 묞제륌 탐색하고 싶지 않은 사람에게 읎것읎 유용하Ʞ륌 바랍니닀.

또 닀륞 사용 사례는 큎래슀가 아닌 사용자 정의 유형 가드 멀버 핚수입니닀.

type Baz = {
    type: "baz"
}
type Bar = {
     type: "bar"
}
type Foo = (Baz|Bar)&{
    isBar: () => this is Bar 
}

í•Žê²° 방법은 ë‚Žê°€ 있얎알 할 곳에 거의 도달하지만 Ʞ얎에 던질 렌치가 하나 더 있습니닀. 닀음곌 같은 읞위적읞 예륌 듀얎 볎십시였.

interface IAutomobileOptions {
  make: string
}

interface ITruckOptions extends IAutomobileOptions {
  bedLength: number
}

export class Automobile<O extends IAutomobileOptions> {
  constructor(public options: O) {}

  static create<T extends typeof Automobile, O extends IAutomobileOptions>(
    this: T,
    options: O
  ): InstanceType<T> {
    return new this(options) as InstanceType<T>
  }
}

export class Truck<O extends ITruckOptions> extends Automobile<O> {
  constructor(truckOptions: O) {
    super(truckOptions)
  }
}

const car = Automobile.create({ make: 'Audi' })
const truck = Truck.create({ make: 'Ford', bedLength: 7 }) // TS Error on Truck

닀음은 였류입니닀.

The 'this' context of type 'typeof Truck' is not assignable to method's 'this' of type 'typeof Automobile'.
  Types of parameters 'truckOptions' and 'options' are incompatible.
    Type 'O' is not assignable to type 'ITruckOptions'.
      Property 'bedLength' is missing in type 'IAutomobileOptions' but required in type 'ITruckOptions'.ts(2684)

Automobile 큎래슀의 create 메서드에는 ITruckOptions ~ O 에 대한 ì°žì¡°ê°€ 없Ʞ 때묞에 읎것읎 의믞가 있습니닀. ê·ž 묞제에 대한 í•Žê²° 방법?

음반적윌로 생성자에 대한 확장 큎래슀의 옵션은 Ʞ볞 큎래슀의 옵션 읞터페읎슀륌 확장하므로 Ʞ볞 큎래슀에 대한 맀개변수가 항상 포핚된닀는 것을 알고 있지만 확장에 대한 맀개변수륌 포핚하는지 확읞하는 안정적읞 방법읎 없습니닀. 등꞉.

나는 또한 상속 큎래슀의 예상 입력 및 반환 유형에 대핮 알늬Ʞ 위핎 큎래슀륌 확장할 때 메서드륌 재정의하는 데 의졎핎알 했습니닀.

@Jack-Barry가 작동합니닀.

interface IAutomobileOptions {
  make: string
}

interface ITruckOptions extends IAutomobileOptions {
  bedLength: number
}

export class Automobile<O extends IAutomobileOptions> {
  constructor(public options: O) { }

  static create<T extends Automobile<O>, O extends IAutomobileOptions>(
    this: { new(options: O): T; },
    options: O
  ): T {
    return new this(options)
  }
}

export class Truck<O extends ITruckOptions> extends Automobile<O> {
  constructor(truckOptions: O) {
    super(truckOptions)
  }
}

const car = Automobile.create({ make: 'Audi' });
const truck = Truck.create({ make: 'Ford', bedLength: 7 });

귞러나 생성자가 공용읎므로 new Automobile({ make: "Audi" }) 만 수행할 수 있윌므로 여전히 읎상적읎지 않습니닀.

@elderapo 나는 귞것읎 ë‚Žê°€ 필요한 것을 얻는닀고 생각합니닀. 예는 묌론 고안된 것읎지만 _Generics_에 대한 읎핎 부족읎 저륌 조ꞈ ꎎ롭힌 부분을 뎅니닀. 정늬핎죌셔서 감사합니닀!

바띌걎대 읎것읎 닀륞 사람듀에게 도움읎되Ʞ륌 바랍니닀. 개선의 여지가 있윌멎 알렀죌십시였. 읜Ʞ Ʞ능읎 잠재적윌로 타읎핑곌 동Ʞ화되지 않을 수 있Ʞ 때묞에 완벜하지는 않지만 필요한 팚턎에 가장 가깝습니닀.

// Interface to ensure attributes that exist on all descendants
interface IBaseClassAttributes {
  foo: string
}

// Type to provide inferred instance of class
type ThisClass<
  Attributes extends IBaseClassAttributes,
  InstanceType extends BaseClass<Attributes>
> = {
  new (attributes: Attributes): InstanceType
}

// Constructor uses generic A to assign attributes on instances
class BaseClass<A extends IBaseClassAttributes = IBaseClassAttributes> {
  constructor(public attributes: A) {}

  // this returns an instance of type ThisClass
  public static create<A extends IBaseClassAttributes, T extends BaseClass<A>>(
    this: ThisClass<A, T>,
    attributes: A
  ): T {
    // Perform db creation actions here
    return new this(attributes)
  }

  // Note that read function is a place where typechecking could fail you if db
  //   return value does not match
  public static read<A extends IBaseClassAttributes>(id: string): A | null {
    // Perform db retrieval here assign to variable
    const dbReturnValue = {} as A | null
    return dbReturnValue
  }
}

interface IExtendingClassAttributes extends IBaseClassAttributes {
  bar: number
}

// Extend the BaseClass with the extending attributes interface
class ExtendingClass extends BaseClass<IExtendingClassAttributes> {}

// BaseClass
const bc: BaseClass = BaseClass.create({ foo: '' })
const bca: IBaseClassAttributes = BaseClass.read('a') as IBaseClassAttributes
console.log(bc.attributes.foo)
console.log(bca.foo)

// ExtendingClass
// Note that the create and read methods do not have to be overriden,
//  but typechecking still works as expected here
const ec: ExtendingClass = ExtendingClass.create({ foo: 'bar', bar: 0 })
const eca: IExtendingClassAttributes = ExtendingClass.read(
  'a'
) as IExtendingClassAttributes
console.log(ec.attributes.foo)
console.log(ec.attributes.bar)
console.log(eca.foo)
console.log(eca.bar)

읎 팚턎을 나뚞지 CRUD 작업윌로 쉜게 확장할 수 있습니닀.

@Jack-Barry의 예에서 큎래슀의 읞슀턎슀륌 반환하는 read 핚수륌 얻윌렀고 합니닀. 닀음읎 작동할 것윌로 예상했습니닀.

class BaseClass<A extends IBaseClassAttributes = IBaseClassAttributes> {

  public static read<A extends IBaseClassAttributes, T extends BaseClass<A>>(
    this: ThisClass<A, T>,
    id: string,
  ): T | null {
    // Perform db retrieval here assign to variable
    const dbReturnValue = {} as A | null
    if (dbReturnValue === null) {
      return null;
    }
    return this.create(dbReturnValue);
  }
}

하지만 대신 Property 'create' does not exist on type 'ThisClass<A, T>'. 였류가 발생합니닀. 읎 묞제륌 핎결하는 방법에 대한 í•Žê²° 방법읎 있는 사람읎 있습니까?

@everhardt create 메서드는 static 읎므로 읞슀턎슀가 아닌 this 의 class 에서 혞출핎알 합니닀. 슉, 여전히 원하는 유형 검사륌 제공하는 class 핚수에 동적윌로 액섞슀하는 방법에 대한 좋은 í•Žê²° 방법읎 없습니닀.

ë‚Žê°€ 얻을 수있는 가장 가까욎 것은 특히 우아하지 않고 BaseClass.create 의 êž°ì¡Ž type 을 사용할 수 없윌므로 쉜게 동Ʞ화되지 않을 수 있습니닀.

return (this.constructor as unknown as { create: (attributes: A) => T }).create(dbReturnValue)

나는 읎것을 _ 테슀튞하지 _ 하지 않았습니닀 .

@Jack-Barry 귞러멎 this.constructor.create is not a function 륌 얻습니닀.

귞것은 의믞가 있습니닀. Typescript는 this 륌 읞슀턎슀로 핎석하지만 최종 자바 슀크늜튞 파서의 겜우 핚수가 정적읎므로 this 가 큎래슀입니닀.

Jack-Barry의 예에서 가장 영감을 받은 확장은 아닐지 몚륎지만 읎 Playground Link 에서 ë‚Žê°€ 얎떻게 핎결했는지 볌 수 있습니닀.

요점:

  • ThisClass 유형은 BaseClass의 메소드(정적 및 읞슀턎슀 몚두)가 닀형성 'this'와 핚께 사용하렀는 몚든 정적 속성 및 메소드륌 섀명핎알 합니닀.
  • 읞슀턎슀 메서드에서 정적 속성읎나 메서드륌 사용할 때 (this.constructor as ThisClass<A, this>) 륌 사용합니닀.

큎래슀와 ThisClass 유형 몚두에서 정적 메서드 및 속성 유형을 정의핎알 하므로 읎쀑 작업읎지만 저에게는 작동합니닀.

펞집: 놀읎터 링크 수정

PHP는 였래전에 읎 묞제륌 수정했습니닀. 볞읞. 공전. 읎것.

안녕하섞요, 2020년입니닀. _this_ 묞제가 있습니닀. 😛

class Animal { 
  static create() { 
    return new this()
  }
}
class Bunny extends Animal {}
const bugs = Bunny.create() // const bugs: Animal

bugs 가 Bunny 의 읞슀턎슀가 될 것윌로 예상합니닀.

현재 í•Žê²° 방법은 묎엇입니까? 읎 묞제에서 몚든 것을 시도했지만 아묎 것도 핎결되지 않는 것 같습니닀.

업데읎튞 : 읎것은 횚곌가 있었고 this 읞수 정의륌 놓쳀습니닀.

class Animal { 
  static create<T extends typeof Animal>(this: T): InstanceType<T> { 
    return (new this()) as InstanceType<T>
  }
}
class Bunny extends Animal {}
const bugs = Bunny.create() // const bugs: Bunny

묞제는 getter와 setter가 유형 맀개변수륌 가질 수 없닀는 것입니닀.

너묎 장황합니닀.

나는 비슷한 묞제륌 닀룚고 있습니닀. "닀형성 낎부 큎래슀"륌 구현하Ʞ 위핎 ë‚Žê°€ 찟을 수 있는 최선은 닀음곌 같습니닀.

class BaseClass {
  static InnerClass = class BaseInnerClass {};

  static createInnerClass<T extends typeof BaseClass>(this: T) {
    return new this.InnerClass() as InstanceType<T['InnerClass']>;
  }
}

class SubClass extends BaseClass {
  static InnerClass = class SubInnerClass extends BaseClass.InnerClass {};
}

const baseInnerClass = BaseClass.createInnerClass(); // => BaseInnerClass

const subInnerClass = SubClass.createInnerClass(); // => SubInnerClass

잘 작동하는 것 같지만 createInnerClass() 륌 입력하는 것은 낮 생각에 너묎 장황하며 낮 윔드베읎슀에 많은 항목읎 있을 것입니닀. 누구든지 읎 윔드륌 닚순화하는 방법에 대한 아읎디얎가 있습니까?

읎 ì ‘ê·Œ 방식의 묞제는 정적 getter 및 setter에서 작동하지 않는닀는 것입니닀.

정적 속성에 대핮 self. 륌 구현하는 것은 얎떻습니까? 나는 4 년 전에읎 묞제가 있었고 같은 묞제로 같은 슀레드로 돌아 왔습니닀.

@sudommaxime ECMAScript 가 큎래슀에서 this.constructor. 에 대한 별칭윌로 Ʞ볞적윌로 self. 륌 지원하지 않는 한 TypeScript 섀계 목표와 반대로 싀행됩니닀. self 가 공통 변수 읎늄읞 겜우 발생합니닀.

@abdullah-kasim의 솔룚션은 섀명된 대로 작동하는 것 같지만 음반 큎래슀에서 작동하도록 할 수 없습니닀.

class Animal<A> {
  public thing?: A;

  static create<T extends typeof Animal>(this: T): InstanceType<T> {
    return new this() as InstanceType<T>;
  }
}

type Foo = {};
class Bunny extends Animal<Foo> {}

const bunny = Bunny.create(); // typeof bunny is Animal<unknown>
bunny.thing;                  // unknown :(

   __     __
  /_/|   |\_\  
   |U|___|U|
   |       |
   | ,   , |
  (  = Y =  )
   |   `  |
  /|       |\
  \| |   | |/
 (_|_|___|_|_)
   '"'   '"'

욎읎 없읎 잠시 고믌핎 볎았윌므로 읎것읎 가능한지 생각핎죌시멎 감사하겠습니닀.

@stevehanson 읎것읎 당신에게 횚곌가 있습니까?

class Animal<A> {
  public thing?: A;

  static create<T>(this: new () => T): T {
    return new this() as T;
  }
}

type Foo = {asd: 123};
class Bunny extends Animal<Foo> {
    public hiya: string = "hi there"
}

const bunny = Bunny.create()


bunny.thing

const test = bunny.thing?.asd

const hiya = bunny.hiya

typescript 놀읎터에서 읎것을 테슀튞했습니닀.

읎 링크에서 영감:
https://selleo.com/til/posts/gll9bsvjcj-generic-with-class-as-argument-and-returning-instance

귞늬고 T 가 큎래슀 자첎띌는 것을 얎떻게 암시했는지 잘 몚륎겠습니닀 . 펞집: 아, 자동 this 맀개변수가 항상 큎래슀 자첎륌 전달하Ʞ 때묞에 T륌 암시하는 것윌로 Ʞ억했습니닀.

@abdullah-kasim 작동했습니닀! 우와, 고마워요! 낮 특정 겜우에 낮 생성자는 읞수륌 췚하므로 닀륞 사람에게 도움읎 될 겜우륌 대비하여 닀음곌 같읎 표시되었습니닀.

  static define<C, T, F = any, I = any>(
    this: new (generator: GeneratorFn<T, F, I>) => C,
    generator: GeneratorFn<T, F, I>,
  ): C {
    return new this(generator);
  }

여Ʞ에 있는 음부 솔룚션은 닀음에서 읞수륌 전달할 수 없Ʞ 때묞에 정적 getter에서 작동하지 않습니닀.

아래 예에서 default 정적 getter륌 상위 큎래슀로 읎동하는 방법은 묎엇입니까?

class Letters {
  alpha: string = 'alpha'
  beta?: string
  gamma?: string
  static get default () {
    return new this()
  }
}

const x = Letters.default.alpha;

읎것은 구묞 개선을 고렀한닀멎 고렀할 가치가 있는 것음 수 있습니닀.

ꎀ렚 가능성: @abdullah-kasim 의 예제에 닀륞 추상화 계잵을 추가하는 데 얎렀움을 겪고 있습니닀. 볞질적윌로 저는 Animal 륌 읞터페읎슀로 바꟞고 Bunny 가 자신의 정적 create() $ 을 정의하도록 허용하고 싶습니닀.

닀음은 싀용적읞 예입니닀(토끌 비유륌 포Ʞ한 것을 용서하십시였!). 나는 몇 가지 닀륞 묞서 유형을 정의할 수 있Ʞ륌 원하고 각각은 묞자엎을 묞서 읞슀턎슀로 바꟞는 정적 팩토늬 메소드륌 정의할 수 있얎알 합니닀. 묞서 유형읎 닀륞 묞서 유형읎 아닌 자첎에 대핎서만 파서륌 정의핎알 한닀고 강제하고 싶습니닀.

(아래 예의 유형은 정확하지 않습니닀. 바띌걎대 ë‚Žê°€ 달성하렀는 것읎 충분히 명확하Ʞ륌 바랍니닀.)

interface ParseableDoc {
    parse<T>(this: new () => T, serialized:string): T|null;
}

interface Doc {
    getMetadata():string;
}

// EXPECT: no error!
const MarkdownDoc:ParseableDoc = class implements Doc {
    constructor(private meta:string){ };
    getMetadata():string { return this.meta; };

    static parse(serialized:string):typeof MarkdownDoc | null {
        // do something specific
        return null;
    }
}

// EXPECT: type error, since class defines no static parse()
const MissingParseDoc:ParseableDoc = class implements Doc {
    constructor(private meta:string){ };
    getMetadata():string { return this.meta; };
}

// EXPECT: type error, since parse() should return a MismatchedDoc
const MismatchDoc: ParseableDoc = class implements Doc {
    constructor(private meta:string){ };
    getMetadata():string { return this.meta; };

    static parse(serialized:string):typeof MismatchDoc | null {
        // do something specific
        return null;
    }
}

(제 생각에는) 닀음곌 같읎 ì“ž 수 있Ʞ륌 바랍니닀.

interface ParseableDoc {
    getMetadata():string;
    static parse<T extends ParseableDoc>(this: new () => T, serialized:string): T|null;
}

class MarkdownDoc implements ParseableDoc {
    getMetadata():string { return ""; }

    static parse(serialized:string):MarkdownDoc|null {
        // do something specific
        return null;
    }
}

여Ʞ에서도 í•Žê²° 방법읎 가능한지 알 수 있습니까?

펞집: 가능한 í•Žê²° 방법

StackOverflow의 또 닀륞 사용 사례
음반 조회 테읎랔 큎래슀륌 섀계하Ʞ 위핎.

// Generic part
abstract class Table<T extends Model> {
    instances: Map<number, T> = new Map();
}
abstract class Model {
    constructor(
        public readonly id: number,
        public table: Table<this>  // Error
    ) { 
        table.instances.set(id, this);
    }
}

// Example: a table of Person objects
class Person extends Model {
    constructor(
        id: number,
        table: Table<this>,  // Error
        public name: string
    ) {
        super(id, table);
    }
}
class PersonTable extends Table<Person> {}

const personTable = new PersonTable();
const person = new Person(0, personTable, 'John Doe');

// Note: the idea of using `this` as generic type argument is to guarantee
// that other models cannot be added to a table of persons, e.g. this would fail:
//     class SomeModel extends Model { prop = 0; }
//     const someModel = new SomeModel(1, person.table);
//                                        ^^^^^^^^^^^^

@Think7 읎 2016년 5월 29음에 댓Ꞁ을 낚게습니닀.
😰 읎게 아직도 수정/추가가 안되었닀는게 믿Ʞ지 않는닀.....

ㅋ
2020년읎 왔닀!

읎것은 우슀ꜝ슀럜고 믞친 짓입니닀. 2020년읎넀요. 4년읎 지난 지ꞈ, 왜 안 고쳐졌을까요?

닀음곌 같은 것을 구현하지 않는 읎유

class Model {
  static create(){
     return new static()
  }
  //or
  static create(): this {
     return new this()
  }
}

class User extends Model {
  //...
}

let user = new User.create() // type === User
읎 페읎지가 도움읎 되었나요?
0 / 5 - 0 등꞉