using 키워드는 스코프를 벗어날 때 자동으로 리소스를 해제 하는 TC39 stage 3 제안입니다. TypeScript 5.2부터 지원합니다.

문제: 수동 리소스 관리

TYPESCRIPT
// ❌ 파일 핸들이나 DB 연결을 수동으로 닫아야 함
const handle = openFile('data.txt');
try {
  const data = handle.read();
  processData(data);
} finally {
  handle.close(); // 항상 닫아야 함 — 잊기 쉬움
}

using으로 자동 해제

TYPESCRIPT
// ✅ using 키워드 — 스코프 끝에서 자동 해제
{
  using handle = openFile('data.txt');
  const data = handle.read();
  processData(data);
} // ← 여기서 자동으로 handle[Symbol.dispose]() 호출

Disposable 인터페이스

using을 사용하려면 객체가 Disposable 인터페이스를 구현해야 합니다.

TYPESCRIPT
// 동기 해제
interface Disposable {
  [Symbol.dispose](): void;
}

// 비동기 해제
interface AsyncDisposable {
  [Symbol.asyncDispose](): Promise<void>;
}

구현 예시

TYPESCRIPT
class FileHandle implements Disposable {
  private closed = false;

  constructor(private path: string) {
    console.log(`파일 열기: ${path}`);
  }

  read(): string {
    if (this.closed) throw new Error('이미 닫힌 파일');
    return '파일 내용';
  }

  [Symbol.dispose](): void {
    if (!this.closed) {
      console.log(`파일 닫기: ${this.path}`);
      this.closed = true;
    }
  }
}

// 사용
function processFile() {
  using file = new FileHandle('data.txt');
  // 파일 열기: data.txt
  const data = file.read();
  console.log(data);
  // 함수 끝에서 자동: 파일 닫기: data.txt
}

await using (비동기 해제)

TYPESCRIPT
class DatabaseConnection implements AsyncDisposable {
  private connected = true;

  static async connect(url: string): Promise<DatabaseConnection> {
    console.log(`DB 연결: ${url}`);
    return new DatabaseConnection();
  }

  async query(sql: string): Promise<any[]> {
    if (!this.connected) throw new Error('연결 끊김');
    return []; // 쿼리 결과
  }

  async [Symbol.asyncDispose](): Promise<void> {
    if (this.connected) {
      console.log('DB 연결 해제');
      this.connected = false;
    }
  }
}

// 사용
async function fetchData() {
  await using db = await DatabaseConnection.connect('postgres://localhost:5432');
  const users = await db.query('SELECT * FROM users');
  console.log(users);
} // ← 자동으로 db[Symbol.asyncDispose]() 호출

DisposableStack

여러 리소스를 함께 관리할 수 있는 컨테이너입니다.

TYPESCRIPT
function setupServer() {
  using stack = new DisposableStack();

  // 여러 리소스를 스택에 추가
  const db = stack.use(new DatabasePool());
  const cache = stack.use(new CacheConnection());
  const logger = stack.use(new FileLogger());

  // 추가 정리 로직도 등록 가능
  stack.defer(() => {
    console.log('서버 종료 정리 완료');
  });

  return { db, cache, logger };
} // ← 스택에 등록된 모든 리소스가 역순으로 해제됨

실전 활용

임시 파일 관리

TYPESCRIPT
class TempFile implements Disposable {
  public path: string;

  constructor(prefix: string) {
    this.path = `/tmp/${prefix}_${Date.now()}`;
    // 임시 파일 생성
    writeFileSync(this.path, '');
  }

  [Symbol.dispose](): void {
    // 자동으로 임시 파일 삭제
    if (existsSync(this.path)) {
      unlinkSync(this.path);
    }
  }
}

function processWithTempFile() {
  using temp = new TempFile('upload');
  writeFileSync(temp.path, '임시 데이터');
  // 처리...
} // ← temp 파일 자동 삭제

락(Lock) 관리

TYPESCRIPT
class Lock implements Disposable {
  private released = false;

  constructor(private resource: string) {
    console.log(`락 획득: ${resource}`);
  }

  [Symbol.dispose](): void {
    if (!this.released) {
      console.log(`락 해제: ${this.resource}`);
      this.released = true;
    }
  }
}

function criticalSection() {
  using lock = new Lock('shared-resource');
  // 임계 구역 코드
  // ...
} // ← 자동으로 락 해제 (예외가 발생해도)

타이머 / 인터벌

TYPESCRIPT
class Interval implements Disposable {
  private id: ReturnType<typeof setInterval>;

  constructor(callback: () => void, ms: number) {
    this.id = setInterval(callback, ms);
  }

  [Symbol.dispose](): void {
    clearInterval(this.id);
  }
}

function monitorHealth() {
  using healthCheck = new Interval(() => {
    console.log('헬스 체크...');
  }, 5000);

  // 다른 작업...
} // ← 자동으로 인터벌 정리

tsconfig 설정

JSON
{
  "compilerOptions": {
    "target": "ES2022",
    "lib": ["ES2022", "ESNext.Disposable"]
  }
}

libESNext.Disposable을 추가해야 Symbol.disposeDisposable 인터페이스를 사용할 수 있습니다.

정리

  • using은 스코프를 벗어날 때 [Symbol.dispose]()를 자동 호출한다
  • await using은 비동기 해제([Symbol.asyncDispose]())를 지원한다
  • DisposableStack으로 여러 리소스를 함께 관리할 수 있다
  • 파일, DB 연결, 락, 타이머 등 정리가 필요한 모든 리소스에 활용 가능하다
  • C#의 using, Python의 with, Java의 try-with-resources와 유사한 개념이다
댓글 로딩 중...