타입스크립트에서는 자바스크립트(ES6)에서 지원하지 않던 인터페이스를 지원한다.
인터페이스를 이용하여 추상화를 할 수 있다.
public interface BackEndFramework {
String crud();
}
@Component
public class SpringBoot implements BackEndFramework {
@Override
public String crud() {
return this.getClass().getSimpleName();
}
}
@Component
@RequiredArgsConstructor
public class Developer {
private final BackEndFramework backEndFramework;
public String develop() {
return backEndFramework.crud();
}
}
BackEndFramework라는 인터페이스를 생성 후 구현체인 SpringBoot를 스프링 빈으로 등록한다.
Developer클래스에서는 추상화된 인터페이스인 BackEndFramework를 의존하고 있다.
테스트 해보자
@SpringBootTest
class DeveloperTest {
@Autowired
Developer developer;
@Test
void DI() {
assertThat(developer.develop()).isEqualTo("SpringBoot");
}
}

export interface BackEndFramework {
crud();
}
@Injectable()
export class NestJS implements BackEndFramework {
crud() {
return NestJS.name;
}
}
@Injectable()
export class Developer {
constructor(
private readonly backEndFramework: BackEndFramework,
) {
}
develop() {
return this.backEndFramework.crud();
}
}
@Module({
imports: [],
providers: [Developer, NestJS],
})
export class AppModule {}
스프링때와 마찬가지로 BackEndFramework라는 인터페이스의 구현체인 NestJS를 프로바이더로 등록한다.
Developer클래스에서는 추상화된 인터페이스인 BackEndFramework를 의존하고 있다.
테스트 해보자
describe('DI Test', () => {
let sut: Developer;
beforeEach(async () => {
const app: TestingModule = await Test.createTestingModule({
imports: [AppModule],
}).compile();
sut = app.get<Developer>(Developer);
});
it('DI', async () => {
expect(sut.develop()).toBe('NestJS');
});
});

@Module({
imports: [],
providers: [Developer, {
provide: 'impl', useClass: NestJS,
}],
})
export class AppModule {}
@Injectable()
export class Developer {
constructor(
@Inject('impl') // Inject 데코레이터 사용
private readonly backEndFramework: BackEndFramework,
) {
}
develop() {
return this.backEndFramework.crud();
}
}
일반적으로 프로바이더를 주입 할때, 생성자 주입 패턴을 사용하여 프로바이더를 주입하게된다.
하지만 이 패턴을 사용하려면 클래스를 의존하고 있어야 하며, 인터페이스를 의존하고 있으면 생성자 주입 패턴을 사용할 수 없다.
이럴 경우 위와 같이 문자열 토큰방식으로 프로바이더를 등록 후 의존하고 있는 인터페이스에@Inject('provide') 데코레이터를 달아주면 useClass에 명시한 구현체가 주입된다.

위와 같이 성공적인 결과가 나온다.
위와 같은 방법으로 NestJS에서도 클라이언트 코드의 수정없이 유연하게 구현체를 변경할 수 있게 된다.