Result 타입이 false 대신 boolean입니다. 유니언과 제네릭이 만나면서 분배법칙이 실행되었기 때문인데요. 분배법칙에 따라 IsString<'hi'> | IsString<3>이고, ('hi' extends string ? true : false) | (3 extends string ? true : false)를 수행하면 true | false이므로 최종적으로 boolean이 된 것입니다.
이럴 때는 분배법칙이 일어나지 않게 해야 합니다.
type IsString<T> = [T] extends [string] ? true : false;
type Result = IsString<'hi' | 3>;
// type Result = false
배열로 제네릭을 감싸면 분배법칙이 일어나지 않습니다. ['hi' | 3]이 [string]을 extends하는지 검사하므로 false가 됩니다. 분배법칙을 막는 방법도 기억해두세요.
또 한 가지 기억할 점이 있습니다. 앞에서 설명하지 않았지만, never도 분배법칙의 대상이 됩니다. never가 유니언으로 보이지는 않지만 유니언이라고 생각하는 것이 좋습니다.
type R<T> = T extends string ? true : false;
type RR = R<never>;
// type RR = never