Không inject trực tiếp bằng interface được: interface của TypeScript bị xoá khi compile, không tồn tại lúc runtime nên Nest không có token để tra cứu.
Phải tạo token tường minh bằng string hoặc Symbol, rồi inject bằng @Inject(token).
ts
export const PAYMENT_GATEWAY = Symbol('PAYMENT_GATEWAY')
export interface PaymentGateway {
charge(orderId: string, amount: number): Promise<string>
}ts
@Module({
providers: [
{
provide: PAYMENT_GATEWAY,
useClass: process.env.PAYMENT_DRIVER === 'stripe' ? StripeGateway : SepayGateway,
},
],
exports: [PAYMENT_GATEWAY],
})
export class PaymentModule {}
@Injectable()
export class CheckoutService {
constructor(@Inject(PAYMENT_GATEWAY) private readonly gateway: PaymentGateway) {}
}Symbol an toàn hơn string vì mỗi symbol có định danh runtime riêng, tránh trùng token giữa các thư viện — nhưng phải export từ một file dùng chung để cả nơi đăng ký lẫn nơi inject dùng đúng một instance.
Cần chọn implementation lúc runtime theo config bất đồng bộ thì dùng useFactory với inject: [ConfigService]. Trong test, chỉ cần overrideProvider(PAYMENT_GATEWAY).useValue(mock) là thay được toàn bộ cổng thanh toán.