ìë¹í Ʞ볞ì ìŽì§ë§ ë€íì±ì íì± ë ìœë ì€íìŒ ëªšëž ìì€í
ì 구ííë €ê³ í ë ìì±ì ëë í
í늿/ì ë€ëŠê³Œ íšê» ì¬ì©í ë 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();
ìë§ë ìŽ ë¬žì ë ìŽëŠ¬ìê³ ì¬ìŽ íŽê²° ë°©ë²ìŽ ììµëë€. ê·žë¬í íšíŽì ë¬ì±í ì ìë ë°©ë²ì ëí ì견ì íìí©ëë€.
ëŽ ë³Žížì í¬êž°ì 몚ìì ë§€ì° ë¹ì·í©ëë€! ìŽìŽ!
ìíŒíŽëì€ì í©í 늬 ë©ìëë ìëžíŽëì€ì ì ìžì€íŽì€ë¥Œ ë°íí©ëë€. ëŽ ìœëì êž°ë¥ì ìëíì§ë§ ë°í ì íì ìºì€í íŽìŒ í©ëë€.
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;
}
}
ììëš: ìì±ì 맀ê°ë³ìì ì¬ì©í ì ììµëë€.
íŽê²°íê³ ì íë 묞ì :
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
ì ëìŒí ì믞륌 ê°ë ê²œì° ì ì ë©ìëì ëìŒíì§ ìì ìŽì ë 묎ìì
ëê¹?
ì°ëŠ¬ë ëë ë§ì ì§ë©ŽíŽ ììŒë©° ìž ê°ì§ ìµì ìŽ ììµëë€.
this
ë ë€ë¥ž 컚í
ì€ížìì ë€ë¥ž ê²ì ì믞í©ëë€(íŒë).self
ëë static
ì ê°ì ì í€ìë ëì
ì ì ë©ìë ì ìì ë°íì ì믞륌 ë°ìíêž° ë묞ì ìž ë²ì§ž ì ê·Œ ë°©ìì ì íží©ëë€.
ëí ì¬ìŽížë¥Œ ì ìíë ëì ì¬ì© ì¬ìŽížìì ì€ë¥ë¥Œ ì°Ÿìë
ëë€. ìŠ, ìŽ ì£Œì ììì ê°ìŽ ì€ë¥ë 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 });
@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
ê°ì¥ ì ì©í ëêž
ìŽ ë¬žì ê° ë«í ìŽì ê° ììµëê¹?
ë€íì±ìŽ ì ì ìì ìëíì§ ìëë€ë ì¬ì€ì ëŽ ìê°ì ìŽ êž°ë¥ì DOAë¡ ë§ëëë€. ëë ì§êžê¹ì§ ìžì€íŽì€ ë©€ë²ì ëíŽ ë€íì±ìŽ ì€ì ë¡ íìíì§ ììì§ë§ ì ì ì²ëŠ¬ ìì€í ìŽ ìŽêž°ì ìì±ëìêž° ë묞ì ì ì ì ëíŽ ëª ì£Œë§ë€ íìíìµëë€. ìŽ êž°ë¥ìŽ ë°íëìì ë ëë ë§€ì° êž°ë»€ì§ë§, ëì€ì ìŽ êž°ë¥ìŽ ìžì€íŽì€ 구ì±ììê²ë§ ìëíë€ë ì¬ì€ì ìê³ ë ì€ë§íìµëë€.
ì¬ì© ì¬ë¡ë ë§€ì° êž°ë³žì ìŽê³ ë§€ì° ìŒë°ì ì ëë€. ê°ëší í©í 늬 ë©ìë륌 ê³ ë €íììì€.
ìŽ ìì ìì ì ë ê° ììììì 못ìꞎ ìºì€í ìŽë
static create()
ë©ìë륌 ì¬ì©íìµëë€. ìŽ êž°ë¥ìŽ ììŒë©Ž ìžìŽì ìì±ëê° ìë¹í ëšìŽì§ë ê²ì²ëŒ 볎ì ëë€.