Created
May 7, 2026 06:06
-
-
Save kuboon/3e7756ce318052c07b66f458773f5afb to your computer and use it in GitHub Desktop.
trait & impl for typescript
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| type ImplType<I, M, O> = I & ThisType<I & M & {owner: O}> | |
| type ImplFor<X, O = never> = <I, M = X>(trait: ImplType<I, M, O>) => (model: M, owner?: O) => I & M & {owner: O} | |
| // simple but slow | |
| const MutableImpl = <I, M, O>(trait: ImplType<I, M, O>) => | |
| (model: M, owner?: O) => | |
| Object.setPrototypeOf(model, Object.assign(trait, {owner})) | |
| // better performance | |
| const CopyImpl = <I, M extends Record<string, unknown>, O>(impl: ImplType<I, M, O>) => (model: M, owner?: O) => { | |
| const pdesc: PropertyDescriptorMap = {} | |
| Object.entries(model).forEach(([k, value])=>{ pdesc[k] = {value, writable: true, enumerable: true}}) | |
| pdesc['owner'] = {value: owner, writable: false, enumerable: false} | |
| return Object.create(impl, pdesc); | |
| } | |
| const ImplFor = CopyImpl | |
| // types | |
| type User = {name: string, age: number} | |
| type Group = {id: string, users: User[]} | |
| // impl for User | |
| const userImplGen: ImplFor<User, Group> = ImplFor | |
| const userImpl = userImplGen({ | |
| getName(){ return this.name }, | |
| addAge(){ this._test += this.age }, | |
| _test: 0, | |
| get test() { return this._test }, | |
| usersCount() { return this.owner.users.length } | |
| }) | |
| type UserImpl = ReturnType<typeof userImpl> | |
| // impl for Group | |
| const groupImplGen: ImplFor<Group> = ImplFor | |
| const groupImpl = groupImplGen({ | |
| get userModels(){ return this.users.map((x: User)=>userImpl(x, this))} | |
| }) | |
| // data | |
| const user: User = {name: 'namae', age: 17} | |
| const group: Group = {id: 'test', users: [user]} | |
| // binding | |
| const groupModel = groupImpl(group) | |
| console.log(groupModel.users) | |
| console.log(groupModel.userModels[0].usersCount()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
https://www.typescriptlang.org/play/?#code/C4TwDgpgBAkgtmANgFXBAPDANFAsjgeQD4oBeWKAMimQAsBLAZ1Ukyr3YG8B7AdwDsIAJwBcUAgF8iAKFCRYCRADFuQ9AA1CZKIIBuwkuUw5c29UQAUwIQEN6wMfCQsM2PISIBKMiQtxuACYQiGL4UHyCQgD8YgTepCQw7KbUPALCsRLS0gD0OVCM9IrQAEYArsAFiHzSAMbc-IyVuBU2JYgQTojaxu7iltZ2DgrOaL1hxPEyUFB+gcGhOBHCMeJTUNIzBCUAVhC1wAB0jBDAAApC3MBXaAQAZnNBiIS7+0c2jIUA5vxWtvY4NKRCSeTzZPJQEqnYDCKCQIR3VRwGz8WoQOoNJpQADC3DAIC6PTcpggAA8YfwAowoAAlfaqALoJpCej8L44Mr8ADW-AiRA8FiKSEcihc4w860eCz6y2isXWnE2UHqjUqYCCjFqYgueOEoAAIhBNSywNchLgbGBtJwsltXgdDhB+NZ6EapYhPIdEUIAKI2Wq0CwWADaXJwuhsiDKEAAup4Epw4RraqGY9aI1GIDheCzgG0OmJrNGcE6ynBhPmIIWhNGJCCleqjSmAOSy5tp8icDPRsSy7O5ytiO6Rk4l-hlivtKtQYeIE62qBCU5lIT8cT2o61Jc2GGCxQ4RuazwAbmkWRVWK6KiE2lx+K64PyciNsjQUAAqicb53+DZy2JmVZdkoBsL5p3HOAoSELJnygABxS4yitTt6ACACXTZDkv0YMRP2EYMYyyXJ8iFbpvQ-L8MVVKAyi-Lo4KdEUkGvdA8KEHAEO4JDDBGZRVCorFaOEQlyCEoR6KdCxFRmMDgAAOT-CALE8RMl2AFc12ABhGEOX9yygCQsCVGwAgCABBMDlMTLSmEOAB9GEsQAanIGydNA6BDKVByjWGAAGIyZNOKBHOAZSoFU5dVxC7T7NCgzApo7DcU5MLvEi9Torcw5ZUOMSdI6NktIMs8wVgtiRNpKL+DFZ9uDuJLhMUGRiKgUiZ1UeDELAATKi+bqJP4Ji+LUTjuO0K9+IvPqBsUbR+q4sBBqkpVZMa815jnKzF2qmLbPyw5kTAINSVwr94yIMSugsUkcDc0EsnrVqAh3GxevWs7YR-RSxGbPSbAgZscA8sQAEYAHZz0xGbFrEMbkIi1DftCoH1pwqBgzEwjH0hVkAiA96FqQ3BNvm2akAsImwDBC9uA6Q5qi+SnupJp48uwmnMTpiAGe4JmqdZ4J2eEQW52DPyY2FoRGBS51lLBIA