Created
December 16, 2018 09:59
-
-
Save Kesin11/47d8c90fcbe35cbc147d91c4a406a89f to your computer and use it in GitHub Desktop.
TypeScriptのGenericsの習作
This file contains 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
interface CollectionSchema { | |
_proto: any | |
path: string | |
sub ?: { | |
[prop: string]: CreateCollection<any> , | |
} | |
} | |
type CreateCollection<T> = (parentPath: string) => Collection<T extends CollectionSchema ? T: never> | |
class Collection<T extends CollectionSchema> { | |
public path: string | |
public sub?: { | |
[Key in keyof T['sub']]: CreateCollection<any>; | |
} | |
constructor (path: string, sub?: {[Key in keyof T['sub']]: CreateCollection<any>}) { | |
this.path = path | |
this.sub = sub | |
} | |
public fetch (): T['_proto'] { | |
// 実際はFirestoreからフェッチしたオブジェクトを返す | |
return { id: 1, name: 'dummy' } as T['_proto'] | |
} | |
public subcollection<Key extends keyof T['sub']> (key: Key): T['sub'][Key] | undefined { | |
if (this.sub) return this.sub[key] as unknown as T['sub'][Key] | |
return | |
} | |
} | |
// ここからCollectionを使う側のコード | |
interface User { | |
id: number, | |
name: string, | |
} | |
interface Book { | |
id: number, | |
title: string | |
} | |
interface MySchema { | |
_proto: User // 実装コードには不要だが、型を推論するために型の世界でどうしても必要 | |
path: string | |
sub: { | |
friend: CreateCollection<UserSchema> | |
book: CreateCollection<BookSchema>, | |
} | |
} | |
interface UserSchema { | |
_proto: User | |
path: string | |
} | |
interface BookSchema { | |
_proto: Book, | |
path: string | |
} | |
const userCollection = new Collection<MySchema>( | |
'user', | |
{ | |
// サブコレクションは本当は↓のようなパスになるので、 | |
// parentの情報を入れてCollectionを作る必要があるのでparentPathを受け取っているが、今は省略 | |
// user/{user_id}/friend/{user_friend_id} | |
// user/{user_id}/book/{user_book_id} | |
friend: (parentPath: string) => new Collection<UserSchema>('friend'), | |
book: (parentPath: string) => new Collection<BookSchema>('book'), | |
}, | |
) | |
const userBookCollection = userCollection.subcollection('book')!('alice') // Collection<BookSchema> | |
const userBook = userBookCollection.fetch() // Bookと推論されたので完成 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment