Slide 1

Slide 1 text

Fukuoka.ts #1 TS TypeScriptͰMixin PatternΛ࢖͏ Tomohisa Oda — GMO Pepabo, Inc. / June 18th 2019

Slide 2

Slide 2 text

Fukuoka.ts #1 linyows / Tomohisa Oda GMO Pepabo, Inc.: Principal Engineer Blog: https://tomohisaoda.com 2

Slide 3

Slide 3 text

Fukuoka.ts #1 Fukuoka.go Organizer 3 https://fukuokago.dev/ ͜ͷՆʢʣʹFGNͰ Go ConferenceΛ෱ԬͰ։࠵͠·͢ https://fukuoka.gocon.jp/ ͜ͷαΠτ͸ɺNuxt.jsͱ TypeScriptͰ࡞͍ͬͯͯɺGitHub ͷPublic RepositoryͰ͢

Slide 4

Slide 4 text

Fukuoka.ts #1 Mixinύλʔϯ࢖͍ͬͯ·͔͢ʁMixinͬͯΘ͔Γ·͢ΑͶʁ 4

Slide 5

Slide 5 text

Fukuoka.ts #1 lMixin͸ɺProgrammer͕ClassʹίʔυΛૠೖ͢Δ͜ͱΛՄೳʹ͢Δ ݴޠͷ֓೦Ͱ͢ɻMixin Programming͸ɺιϑτ΢ΣΞ։ൃͷελΠϧ Ͱɺػೳͷ୯Ґ͸Class಺Ͱ࡞੒͞Ε͔ͯΒଞͷClassͱMix͞Ε·͢ɻz h t t p s : / / e n . w i k i p e d i a . o r g / w i k i / M i x i n # D e f i n i t i o n 5

Slide 6

Slide 6 text

Fukuoka.ts #1 Mixin 6 Inheritence ༗޲ඇ८ճάϥϑ ໦ߏ଄

Slide 7

Slide 7 text

Fukuoka.ts #1 ͭ·ΓɺػೳʢৼΔ෣͍ʣΛ੾Γग़ͯͦ͠ͷৼΔ෣͍Λ͋ΔClassʹऔΓࠐΉɻ ·ͨɺܧঝͷΑ͏ͳɺߏ଄Խ͞Εͨ਌ࢠؔ܎Ͱ͸දݱͰ͖ͳ͍ݱ࣮ੈքͷෳࡶੑΛิ͏ɻ 7

Slide 8

Slide 8 text

Fukuoka.ts #1 Mixins͸Կ͕خ͍͠ͷ͔ w ৼΔ෣͍ʹ໊લΛ͚ͭͯ෼ׂͰ͖Δ w ૊Έ߹Θͤͯ࢖͏ͷͰίʔυͷ࠶ར༻ੑ͕ߴ͍ w খ͘͞෼ׂՄೳͳͷͰ؅ཧ͠΍͍͢ w ݺͼग़͠ଆʹػೳͷબ୒͕Մೳ 8 P I G E O N N O I S Y C AT M O VA B L E F LYA B L E

Slide 9

Slide 9 text

Fukuoka.ts #1 9 "Mixins first appeared in the Symbolics's object-oriented Flavors system (developed by Howard Cannon), which was an approach to object-orientation used in Lisp Machine Lisp. The name was inspired by Steve's Ice Cream Parlor in Somerville, Massachusetts: The owner of the ice cream shop offered a basic flavor of ice cream (vanilla, chocolate, etc.) and blended in a combination of extra items (nuts, cookies, fudge, etc.) and called the item a "mix-in", his own trademarked term at the time."

Slide 10

Slide 10 text

Fukuoka.ts #1 Usecase w ༷ʑͳཁٻʹରԠ͢ΔϏδωεϩδοΫ w େ͖Ίͷ"1*ΫϥΠΞϯτ ྫHJUIVCDPNQFQBCPHNPQH 10

Slide 11

Slide 11 text

Fukuoka.ts #1 Exampleʢͦͷલʹʣ 11 ϋϯυϒοΫͷํ͸ྗٕʢJSʣͰmixinΛ࣮ݱ͍ͯͯ͠ɺΠϯλʔϑΣʔεΛࣗલͰॻ͘ํ๏ʹͳ͍ͬͯ· ͢ɻ2017೥ͷTS2.2Ͱ͸Mixinsͷਖ਼ࣜͳܕαϙʔτ͕͞Ε͍ͯΔͷͰɺͦͪΒΛࢀߟʹ͠·͠ΐ͏ɻ class Disposable { isDisposed: boolean; dispose() { this.isDisposed = true; } } class Activatable { isActive: boolean; activate() { this.isActive = true; } deactivate() { this.isActive = false; } } class SmartObject implements Disposable, Activatable { constructor() { setInterval(() => console.log(this.isActive + " : " + this.isDisposed), 500); } interact() { this.activate(); } isDisposed: boolean = false; dispose: () => void; isActive: boolean = false; activate: () => void; deactivate: () => void; } applyMixins(SmartObject, [Disposable, Activatable]); let smartObj = new SmartObject(); setTimeout(() => smartObj.interact(), 1000); function applyMixins(derivedCtor: any, baseCtors: any[]) { baseCtors.forEach(baseCtor => { Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => { Object.defineProperty(derivedCtor.prototype, name, Object.getOwnPropertyDescriptor(baseCtor.prototype, name)); }); }); }

Slide 12

Slide 12 text

Fukuoka.ts #1 12 1 | class Point { 2 | constructor(public x: number, public y: number) {} 3 | } 4 | 5 | class Person { 6 | constructor(public name: string) {} 7 | } 8 | 9 | type Constructor = new(...args: any[]) => T; 10 | 11 | function Tagged>(Base: T) { 12 | return class extends Base { 13 | _tag: string; 14 | constructor(...args: any[]) { 15 | super(...args); 16 | this._tag = ""; 17 | } 18 | } 19 | } Example: https://github.com/Microsoft/TypeScript/pull/13743 .JYJO$POTUSVDUPSܕΛఆٛ͢Δ δΣωϦΫε͸.JYJO$POTUSVDUPSͷ੍໿Λड͚Δ

Slide 13

Slide 13 text

Fukuoka.ts #1 21 | const TaggedPoint = Tagged(Point); 22 | 23 | let point = new TaggedPoint(10, 20); 24 | point._tag = "hello"; 25 | 26 | class Customer extends Tagged(Person) { 27 | accountBalance: number; 28 | } 29 | 30 | let customer = new Customer("Joe"); 31 | customer._tag = "test"; 32 | customer.accountBalance = 0; 13 Example: https://github.com/Microsoft/TypeScript/pull/13743 function Tagged(Base: typeof Point): { new (...args: any[]): Tagged.(Anonymous class); prototype: Tagged.(Anonymous class); } & typeof Point const TaggedPoint: new (x: number, y: number) => Tagged.(Anonymous class) & Point ͜ͷ··Ͱ͸Anonymous ClassʹͳΔ

Slide 14

Slide 14 text

Fukuoka.ts #1 14 1 | interface Tagged { 2 | _tag: string; 3 | } 4 | 5 | function Tagged>(Base: T): Constructor & T { 6 | return class extends Base { 7 | _tag: string; 8 | constructor(...args: any[]) { 9 | super(...args); 10 | this._tag = ""; 11 | } 12 | } 13 | } 14 | 15 | const TaggedPoint: Constructor & typeof Point = Tagged(Point); 16 | let point: Tagged & Point = new TaggedPoint(10, 20); 17 | point._tag = "hello"; Example: https://github.com/Microsoft/TypeScript/pull/13743 function Tagged(Base: typeof Point): Constructor & typeof Point const TaggedPoint: new (x: number, y: number) => Tagged & Point ໭ΓͷܕʹλΠϓύϥϝʔλʹఆٛͨ͠Intefaceͱ Intersection TypeΛઃఆ͢Δ͜ͱͰɺܕ҆શʹͳΔ

Slide 15

Slide 15 text

Fukuoka.ts #1 15 1 | interface Point { 2 | x: number; 3 | y: number; 4 | } 5 | 6 | const WithLocation = >(Base: T) => 7 | class extends Base { 8 | getLocation(): [number, number] { 9 | return [this.x, this.y]; 10 | } 11 | } Example: https://github.com/Microsoft/TypeScript/pull/13743 Mixin Class͸ɺλΠϓύϥϝʔλͷ੍໿ͰίϯετϥΫτγάχνϟͷ໭Γ஋ͷܕΛࢦఆ͢Δ͜ͱͰɺ ࠞࡏͤ͞Δ͜ͱ͕Ͱ͖ΔΫϥεͷܕΛ੍ݶͰ͖Δ

Slide 16

Slide 16 text

Fukuoka.ts #1 ໰୊఺ w ن໛͕େ͖͘ͳΔͱϏϧυ͕࣌ؒ஗͘ͳΔ w ࠶ؼܕ໰୊ w δΣωϦΫεҾ਺໰୊ w σίϨʔλʔ໰୊ via: https://www.bryntum.com/blog/the-mixin-pattern-in-typescript-all-you-need-to-know/ by SamuraiJack 16

Slide 17

Slide 17 text

Fukuoka.ts #1 ·ͱΊ w ΦϒδΣΫτࢦ޲ϓϩάϥϛϯάʹ͓͚ΔMixinͷఆٛΛ͓͞Β͍͠·ͨ͠ w TypeScriptͰ͸ݴޠ࢓༷ͱͯ͠MixinΛ؆୯ʹ࢖͑ΔΠϯλʔϑΣʔεΛ࣋ͬͯ ͍ΔΘ͚Ͱ͸͋Γ·ͤΜ͕ɺMixinύλʔϯ͕Ͱ͖Δ͜ͱ͕Θ͔Γ·ͨ͠ w ·ͨɺܕ҆શͰ͋ͬͨΓɺػೳΛબ୒ͯ͠ఏڙͨ͠Γɺ։ൃͷதͰ༗༻ͦ͏Ͱ͋ Δ͜ͱ͕Θ͔Γ·ͨ͠ w ࢖͍ॴΛΘ͖·͑ɺTypeScriptΛ͔ͭͬͨ։ൃઃܭͷҾ͖ग़͠ͷ̍ͭʹͲ͏ͧ 17