Factory関数でインスタンス生成時に発生する型エラーを解決したい
TypeScriptを使用し、クライアント側からajax操作時、インターフェイスを統一したモジュールを作成しています。
その際以下のエラーメッセージが、エディタ(VSCode)上で表示されます。
発生している問題・エラーメッセージ
型 'PostsRepository | UsersRepository' を型 'repositoryTypes[T]' に割り当てることはできません。 型 'PostsRepository' を型 'repositoryTypes[T]' に割り当てることはできません。 型 'PostsRepository' を型 'PostsRepository & UsersRepository' に割り当てることはできません。 型 'PostsRepository' を型 'UsersRepository' に割り当てることはできません。 プロパティ 'all' の型に互換性がありません。 型 '() => Promise<IPostsModel[]>' を型 '() => Promise<IUsersModel[]>' に割り当てることはできません。 型 'Promise<IPostsModel[]>' を型 'Promise<IUsersModel[]>' に割り当てることはできません。 型 'IPostsModel[]' を型 'IUsersModel[]' に割り当てることはできません。 Type 'IPostsModel' is missing the following properties from type 'IUsersModel': age, sex
該当のソースコード
簡易版ですが、作成しているモジュールは以下の構造になっています。
TypeScript
1import axios, { AxiosInstance } from 'axios' 2class Adapter { 3 private request(): AxiosInstance { 4 return axios.create({ 5 baseURL: '/' 6 }) 7 } 8 async get<T, U = void>(endpoint: string, req?: U): Promise<T> { 9 const result = await this.request() 10 .get<T>(endpoint, req) 11 .catch(e => { 12 throw new Error(`${e} at ${endpoint}`) 13 }) 14 return result.data 15 } 16} 17abstract class AbstractRepository<Model, Query> { 18 private adapter: Adapter 19 private rootUri: string 20 constructor(adapter: typeof Adapter, rootUri) { 21 this.rootUri = rootUri 22 this.adapter = new adapter() 23 } 24 public async all() { 25 const result = await this.adapter.get<Model[]>(`${this.rootUri}/`) 26 return result 27 } 28} 29 30export interface IPostsQuery { 31 id?: number 32 name?: string 33} 34 35export interface IPostsModel { 36 id: number 37 name: string 38 title: string 39 context: string 40} 41 42class PostsRepository extends AbstractRepository<IPostsModel, IPostsQuery> { 43 constructor(adapter: typeof Adapter) { 44 const rootUri = 'posts' 45 super(adapter, rootUri) 46 } 47} 48 49interface IUsersQuery { 50 id?: number 51 name?: string 52 age?: string 53} 54 55interface IUsersModel { 56 id: number 57 name: string 58 age: string 59 sex: string 60} 61 62class UsersRepository extends AbstractRepository<IUsersModel, IUsersQuery> { 63 constructor(adapter: typeof Adapter) { 64 const rootUri = 'users' 65 super(adapter, rootUri) 66 } 67} 68 69const repositories = { 70 users: UsersRepository, 71 posts: PostsRepository 72} 73type repositoryTypes = { 74 users: UsersRepository 75 posts: PostsRepository 76} 77function getRepository<T extends keyof repositoryTypes>( 78 name: T 79): repositoryTypes[T] { 80 const result = new repositories[name](Adapter) 81 // この行で前述のエラーメッセージが表示されます 82 return result 83} 84 85const postsRepository = getRepository('users') 86const posts = postsRepository.all() 87
試したこと
tsconfig.jsonの設定変更
baseUrl
の値を.
から./src
に変更したところエラーメッセージは消えましたが@
でのimportがエラーになりました。
getRepository()
関数の戻り値型指定変更
盲目的にgetRepository()
関数の戻り値型指定を以下のように変更してみました。
diff
1 2function getRepository<T extends keyof repositoryTypes>( 3 name: T 4- ): repositoryTypes[T] { 5+ ): UsersRepository | PostsRepository { 6 const result = new repositories[name](Adapter) 7 return result 8}
エラーメッセージは表示されなくなりましたが、getRepository()
関数からの戻り値型がconst postsRepository: UsersRepository | PostsRepository
となり、そもそも実現したいことから離れてしまっているので、この方法は選択しませんでした。
補足情報(FW/ツールのバージョンなど)
- Typescript@3.4.5
- tsconfig.jsonは以下です
json
1 2{ 3 "compilerOptions": { 4 "target": "esnext", 5 "module": "esnext", 6 "resolveJsonModule": true, 7 "strict": true, 8 "jsx": "preserve", 9 "jsxFactory": "h", 10 "importHelpers": true, 11 "moduleResolution": "node", 12 "experimentalDecorators": true, 13 "esModuleInterop": true, 14 "allowSyntheticDefaultImports": true, 15 "sourceMap": true, 16 "baseUrl": ".", 17 "strictPropertyInitialization": false, 18 "noImplicitAny": false, 19 "types": [ 20 "webpack-env", 21 "jest", 22 "json-server", 23 "dotenv", 24 "firebase", 25 "@types/node", 26 "@nuxt/vue-app", 27 ], 28 "paths": { 29 "@/*": [ 30 "./src/*" 31 ], 32 "~/*": [ 33 "./src/*" 34 ] 35 }, 36 "lib": [ 37 "esnext", 38 "dom", 39 "dom.iterable", 40 "scripthost" 41 ] 42 }, 43 "include": [ 44 "**/*.ts", 45 "**/*.tsx", 46 "**/*.vue", 47 "test/**/*.ts", 48 "test/**/*.tsx" 49 ], 50 "exclude": [ 51 "node_modules" 52 ] 53} 54
こちらの解決方法をご存知の方がいらっしゃいましたら、お伝えくださると大変助かります。
何卒よろしくお願い致します。
あなたの回答
tips
プレビュー