판별 가능한 유니언은 각 타입에 kind 같은 리터럴 필드를 둡니다. 그 필드를 검사하면 해당 종류의 필드만 안전하게 사용할 수 있습니다.
데모는 kind가 success면 data, error면 message가 열리는 상태를 번갈아 보여줍니다. 새 종류를 추가하면 처리 분기를 빠뜨리지 않았는지도 확인해야 합니다.
언제 쓰나
서버 응답·상태 머신처럼 종류에 따라 필드 구성이 달라지는 값을 모델링할 때 사용합니다.
공통 태그 필드로 유니언의 각 형태를 구분합니다.
<div class="visual variant" data-step="0"><div class="visual-head"><strong>DISCRIMINANT</strong><i></i></div><div class="visual-scene"><div class="variant-kind mono">kind</div><div class="variant-branches"><div class="variant-ok">success<br><strong>data: 42</strong></div><div class="variant-err">error<br><strong>message</strong></div></div></div><div class="visual-caption"></div><div class="visual-dots"><b></b><b></b><b></b><b></b></div></div>.visual{width:min(95vw,760px);height:min(91vh,330px);padding:clamp(9px,2.5vmin,18px);display:flex;flex-direction:column;gap:clamp(6px,1.7vmin,11px);border:1px solid var(--line);border-radius:13px;background:var(--surface);font:500 clamp(12px,3.4vmin,16px)/1.25 var(--font-sans,-apple-system),sans-serif}
.visual-head{display:flex;align-items:center;justify-content:space-between;gap:8px;min-height:19px;color:var(--accent)}.visual-head strong{font-size:1em}.visual-head i{display:block;width:8px;height:8px;flex:none;border-radius:50%;background:var(--accent);animation:visual-pulse 1.3s infinite}@keyframes visual-pulse{50%{opacity:.25}}
.visual-scene{position:relative;flex:1;min-height:0;overflow:hidden}.visual-caption{min-height:2.4em;display:grid;place-items:center;text-align:center}.visual-dots{display:flex;justify-content:center;gap:4px}.visual-dots b{display:block;width:15px;height:3px;border-radius:3px;background:var(--line)}.visual-dots b.on{background:var(--accent)}
.visual-scene *{box-sizing:border-box}.visual-scene .mono{font-family:ui-monospace,monospace}.visual-scene .muted{color:var(--muted)}.visual-scene .lit{border-color:var(--accent)!important;background:color-mix(in srgb,var(--accent) 14%,var(--surface))!important;color:var(--fg)!important}
.variant .visual-scene{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:6px}.variant-kind{border:1px solid var(--accent);border-radius:6px;padding:5px 14px;color:var(--accent)}.variant-branches{display:flex;gap:12px;width:100%;justify-content:center}.variant-branches div{width:39%;border:1px solid var(--line);border-radius:7px;background:var(--bg);padding:7px 4px;text-align:center;opacity:.4;transition:opacity .3s,transform .3s}.variant-branches strong{font-size:12px}.variant[data-step="0"] .variant-kind,.variant[data-step="1"] .variant-ok,.variant[data-step="2"] .variant-err,.variant[data-step="3"] .variant-ok{opacity:1;transform:translateY(-3px);border-color:var(--accent)}.variant[data-step="0"] .variant-branches div{opacity:.6}const root=document.querySelector('.visual'),cap=root.querySelector('.visual-caption'),dots=[...root.querySelectorAll('.visual-dots b')],captions=["Inspect kind","Success exposes data","Error exposes message","Choose the matching payload"];let step=0;function advance(){root.dataset.step=String(step);cap.textContent=captions[step];dots.forEach((d,i)=>d.classList.toggle('on',i===step));if(root.classList.contains('generic')){root.querySelector('.generic-input').textContent=step===3?'"hi"':'7';root.querySelector('.generic-output').textContent=step===3?'"hi" : string':'7 : number'}if(root.classList.contains('union'))root.querySelector('.set-value').textContent=step%2?'value: "seven"':'value: 7';step=(step+1)%captions.length}advance();let timer=setInterval(advance,1100);root.addEventListener('pointerdown',()=>{clearInterval(timer);advance()})판별 가능한 유니언은 각 타입에 kind 같은 리터럴 필드를 둡니다. 그 필드를 검사하면 해당 종류의 필드만 안전하게 사용할 수 있습니다.
데모는 kind가 success면 data, error면 message가 열리는 상태를 번갈아 보여줍니다. 새 종류를 추가하면 처리 분기를 빠뜨리지 않았는지도 확인해야 합니다.
서버 응답·상태 머신처럼 종류에 따라 필드 구성이 달라지는 값을 모델링할 때 사용합니다.