Skip to content

Instantly share code, notes, and snippets.

@gaogao-9
Last active May 28, 2020 19:54
Show Gist options
  • Save gaogao-9/7ace1680cfe3ed44705028bd014f16ba to your computer and use it in GitHub Desktop.
Save gaogao-9/7ace1680cfe3ed44705028bd014f16ba to your computer and use it in GitHub Desktop.
TypeScriptでデコレータなしでDIするやつ
export type Types = Record<string, symbol>;
export interface IDIContainerBindResult<T> {
to: (value: new () => T) => void;
toStatic: (value: T) => void;
}
export interface IDIContainer {
container: {
[k in Types[keyof Types]]: unknown;
};
isStatic: {
[k in Types[keyof Types]]: boolean;
};
bind<T>(key: Types[keyof Types]): IDIContainerBindResult<T>;
inject<T, U extends Iterable<unknown> = []>(
key: Types[keyof Types],
args?: U,
): T;
}
export const DIContainer: IDIContainer = {
container: {},
isStatic: {},
bind<T>(key: Types[keyof Types]): IDIContainerBindResult<T> {
return {
to(value): void {
DIContainer.container[key] = value;
DIContainer.isStatic[key] = false;
},
toStatic(value): void {
DIContainer.container[key] = value;
DIContainer.isStatic[key] = true;
},
};
},
inject<T, U extends Iterable<unknown> = []>(
key: Types[keyof Types],
args?: U,
): T {
if (!DIContainer.container[key]) {
throw new Error(`コンテナに登録されていないkeyを参照しました。`);
}
return DIContainer.isStatic[key]
? DIContainer.container[key]
: new DIContainer.container[key](...(args || []));
},
};
export const Types = {
Knex: Symbol("Knex"),
Database: Symbol("Database"),
UserRepository: Symbol("UserRepository"),
UserController: Symbol("UserController"),
};
// このファイルに書かれていることは実際はknex側の実装だったり、あるいはテスト用のMock Knexだったりします
export class Knex {
constructor(options: { url: string }) {
/* 以下実際はknex側で実装された何かが続く... */
console.log(options.url);
}
from(query: string): this {
/* 以下実際はknex側で実装された何かが続く... */
console.log(`from: ${query}`);
return this;
}
where(query: string, placeholder: Array<unknown>): this {
/* 以下実際はknex側で実装された何かが続く... */
console.log(`where: ${query} ${placeholder}`);
return this;
}
find<T>(): T {
/* 以下knex側で実装された何かが続く... */
const result: T = ({} as unknown) as T;
return result;
}
}
export interface IDatabaseOptions {
connectionURL: string;
}
export interface IDatabase {
connect(options: IDatabaseOptions): void;
}
import { DIContainer } from "./DIContainer.ts";
import { Types } from "./types.ts";
import { IDatabase, IDatabaseOptions } from "./IDatabase.ts";
import { Knex } from "./Knex.ts";
export interface IKnexDatabase extends IDatabase {
client: Knex;
}
export class KnexDatabase implements IKnexDatabase {
client: Knex;
connect(options: IDatabaseOptions): void {
this.client = DIContainer.inject<Knex, ConstructorParameters<typeof Knex>>(
Types.Knex,
[{ url: options.connectionURL }],
);
}
}
import { IDatabase } from "./IDatabase.ts";
export interface IRepository {
database: IDatabase;
}
export type User = {
id: string;
name: string;
};
import { DIContainer } from "./DIContainer.ts";
import { Types } from "./types.ts";
import { IRepository } from "./IRepository.ts";
import { IKnexDatabase } from "./KnexDatabase.ts";
import { User } from "./User.ts";
export interface IUserRepository extends IRepository {
find(id: string): User;
}
export class UserRepository implements IUserRepository {
database = DIContainer.inject<IKnexDatabase>(Types.Database);
public find(id: string): User {
return this.database.client
.from("user")
.where("user.id = ?", [id])
.find<User>();
}
}
export interface IController {
repository: IRepository;
}
import { DIContainer } from "./DIContainer.ts";
import { Types } from "./types.ts";
import { IController } from "./IController.ts";
import { IUserRepository } from "./UserRepository.ts";
import { User } from "./User.ts";
interface IUserController extends IController {
get(id: string): User;
post(user: User): void;
}
class UserController implements IUserController {
repository = DIContainer.inject<IUserRepository>(Types.UserRepository);
get(id: string): User {
return this.repository.find(id);
}
post(user: User): void {
throw new Error("Method not implemented.");
}
}
import { DIContainer } from "./DIContainer.ts";
import { Types } from "./types.ts";
import { Knex } from "./Knex.ts";
import { KnexDatabase } from "./KnexDatabase.ts";
import { UserRepository } from "./UserRepository.ts";
import { UserController } from "./UserController.ts";
DIContainer.bind(Types.Knex).toStatic(new Knex());
DIContainer.bind(Types.Database).toStatic(new KnexDatabase());
DIContainer.bind(Types.UserRepository).to(UserRepository);
DIContainer.bind(Types.UserController).to(UserController);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment