TypeScript를 활용하여 Assistant API 호출을 streaming 하는 과정에서 오류가 발생했다.
오류 메시지
Property 'text' does not exist on type 'MessageContentDelta'. Property 'text' does not exist on type 'ImageFileDeltaBlock'.
export const streamAIResponse = regionalFunctions.https.onRequest(async (req, resp) => {
...
// OpenAI Thread ID가 없으면 새로 생성
const threadId = clientThreadId ?? (await openai.beta.threads.create({})).id;
// 사용자 메시지 생성
await openai.beta.threads.messages.create(threadId, {
role: 'user',
content: prompt,
});
const stream = await openai.beta.threads.runs.create(
threadId,
{ assistant_id: assistantId, stream: true }
);
// !!!! 오류 발생 !!!!
for await (const event of stream) {
if(event.event === 'thread.message.delta') {
console.log(event.data.delta.content[0].text.value)
}
}
...
);
오류는
event.data.delta.content[0]의 타입인MessageContentDelta타입이 여러 가지 타입 중 하나일 수 있는 유니언 타입으로 정의되어 있기 때문에 발생했다.
export type MessageContentDelta =
| ImageFileDeltaBlock
| TextDeltaBlock
| RefusalDeltaBlock
| ImageURLDeltaBlock;
MessageContentDelta가 여러 타입 중 하나일 수 있기 때문에, TypeScript는 이 객체가 항상 TextDeltaBlock일 것이라고 추론할 수 없다. 각 타입마다 속성이 다를 수 있기 때문이다.
따라서, 아래와 같은 코드에서 문제가 발생한다.
for await (const event of stream) {
if (event.event === 'thread.message.delta') {
console.log(event.data.delta.content[0].text.value); // 오류 발생
}
}
가장 간단한 해결책은 특정 타입으로 명시적으로 캐스팅하는 것이다.
for await (const event of stream) {
if (event.event === 'thread.message.delta') {
const delta = event.data.delta.content[0] as TextDeltaBlock;
console.log(delta.text.value);
}
}
이 방법을 사용하면 TypeScript는 "이 데이터는 TextDeltaBlock이다"라고 이해하게 된다. 그러나, 만약 다른 타입의 데이터가 들어온다면 런타임 에러가 발생할 수 있다.