1195 단어
6 분
작은 스크립트 파일은 Deno를 쓰는 것에 대하여

Node.js에서의 타입스크립트#

Node.js에서 타입스크립트를 쓰려면, 3가지 방법이 있다.

  • 타입스크립트용 REPL을 사용한다.
    • tsx 패키지를 설치해야 한다.
    • tsx 명령어로 타입스크립트 코드를 실행시킨다.
  • 타입스크립트 프로젝트를 생성한다.
    • tsconfig.json 파일을 만들어야 한다.
    • esbuildtsc로 타입스크립트를 자바스크립트로 컴파일해야 한다.
    • 그렇기에, package.json과 node_modules도 필요하다.
    • 컴파일된 자바스크립트 파일을 실행해야 한다.
  • Node.js를 믿는다.
    • 일단 타입스크립트 파일을 실행시킨다.
    • Node.js의 --strip-types를 믿고 실행한다.
    • strip 가능한 코드가 아니라면서, 에러가 난다. alt text
    • 이제 --experimental-transform-types를 쓴다.
    • 매번 플래그 넘겨주려니까 귀찮다.
    • 결국 tsx를 설치한다.
GIF

> 서기관 셰럼, 이건 좀 너무한다고 생각함.

그럼 타입스크립트 왜씀?#

타입스크립트는 자바스크립트보다 빌드 타임에 많은 정보를 알게 된다. 이곳에서 오는 크나큰 장점이 있다.

자동완성

JS는 object의 프로퍼티가 무엇인지 알 수 없다. 그래서 자동완성이 안된다.

TS는 정보를 .ts 파일이나 .d.ts 파일에 모두 담아놓는다. number에는 toFixed가 있고, string에는 toUpperCase가 있다는 것을 알고 있다. toUpperCase는 파라미터를 아무것도 받지 않은 ()=>string 타입의 함수임을 lib.d.ts에 적어놓는다.

JS는 이상한 기교가 있다. 빈 배열과 느낌표, 더하기, 이상한 기호 몇 개로 모든 코드를 만들 수 있다.

[]+[] // ""
[]+{} // "[object Object]"
{}+[] // 0
{}+{} // NaN

이 무슨 쓰레기 언어란 말인가. 타입스크립트 안 쓸 이유가 없지 않나?

> 정체성의 유령도 한물 두물 세물 간 자바스크립트를 버리고 타입스크립트에 어울리는…

빨간약#

하지만 타입스크립트는 딱 하나의 문제점이 있다. 결국 실행을 못 한다.

> 으에엥 타입스크립트 네르지 마세요

그러면 타입스크립트 코드를 자바스크립트 코드로 변환하고, 실행하고, 그걸 반복하면 되지 않을까? 가능하다. Node.js의 --strip-types가 비슷하게 한다. 하지만 이는 const enum과 같은 일부 기능을 지원하지 않는다. --experimental-transform-types 플래그를 써야 한다. 하지만 이름에서 알 수 있듯이 이는 실험적이다. 언제 터져도 이상하지 않다는 것이다.

그렇게 엄청 간단하지는 않은 스크립트#

예시로, hello.ts라는 파일을 만들어보자.

console.log("Hello, world!");

이는 충분히 간단하다. tsx로도 실행할 수 있다. 하지만, 조금 복잡한 스크립트는 어떨까?

openai.ts
const prompt='"크아앙"\n투명드래곤이 울부짖었다.\n\n이 다음 소설의 내용을 이어서 써줘.';
const response = await fetch("https://api.openai.com/v1/chat/completions", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${process.env.OPENAI_API_KEY}`,
},
body: JSON.stringify({
model: "gpt-5-mini",
messages: [{ role: "user", content: prompt }],
}),
});
const data = await response.json();

> 한 동인지 작가의 흑역사를 드러내고 있다.

조금 복잡해진다. 이제 스트리밍도 추가해볼까?

openai.ts
const prompt='"크아앙"\n투명드래곤이 울부짖었다.\n\n이 다음 소설의 내용을 이어서 써줘.';
const response = await fetch("https://api.openai.com/v1/chat/completions", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${process.env.OPENAI_API_KEY}`,
},
body: JSON.stringify({
model: "gpt-5-mini",
messages: [{ role: "user", content: prompt }],
stream: true,
}),
});
const reader = response.body.getReader();
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = new TextDecoder().decode(value);
console.log(chunk);
}

물론 여기서 저 청크 하나하나도 JSON이니까, JSON.parse를 해야 한다. 메세지 델타들에 대해 조금씩 출력하고, 메세지 끝에 도달했는지 확인하는 로직도 필요하다.

Deno를 쓰세요#

tsx는 Node.js다. 라이브러리를 설치하려면, node_modules에 넣어야 한다. 방법은? pnpm add와 package.json 관리, 그리고 기타 귀찮은 파일 관리를 해야 한다.

Deno는 Deno다. 라이브러리를 사용하려면,

import OpenAI from 'jsr:@openai/openai';

이 얼마나 간결한가. Deno로 위 예시를 다시 짜 보자.

import OpenAI from "jsr:@openai/openai";
const client = new OpenAI();
const stream = await client.responses.create({
model: "gpt-5-mini",
input: '"크아앙"\n투명드래곤이 울부짖었다.\n\n이 다음 소설의 내용을 이어서 써줘.',
stream: true,
});
for await (const event of stream) {
console.log(event);
}

타입스크립트? Deno는 된다.

> 긴긴-팔다리의 출몰에 정신을 잃은 셰럼