Python의 any function을 타입 시스템으로 구현하세요
배열을 사용하고 배열의 요소가 참이면 true를 반환합니다. 배열이 비어 있으면 false를 반환합니다
type Falsy=0|''|Record<string,never>|false|undefined|null|[];
type AnyOf<T extends readonly any[]> = true extends (T[number] extends Falsy?false:true)?true:false;
Falsy에는 false로 평가될 수 있는 값을 정의 했다
빈 배열 대신, Record<string,never>를 사용한 이유는, ts에서 모든 타입은 {}를 extends하는 것으로 취급되기 때문이다
타입스크립트는 객체가 어떤 생성자를 통해 생성되었는가, 혹은 어떤 방식으로 생성되었는가와 상관없이 해당 객체의 멤버가 같으면 같은 타입으로 본다.
타입스크립트의 타입에서 {}은 어떠한 키, 밸류도 가지지 않은 객체 타입이다.
그런데, js에서는 null과 undefined를 제외한 다른 값들은 그 값을 사용할 때, 그 값에 해당하는 객체로 자동을 감싸준다(오토박싱)
(ex:1=>Number(1) 그래서 (1).toString() 등의 함수가 가능한 것)
그러므로 1,false 등과 같은 원시형 리터럴들도 {}를 상속할 수 있는 것이다.
정말 빈 객체를 의미하고 싶으면 Record<string,never>, 혹은 이것과 유사한 타입을 지정할 수 있다.
AnyOf의 구현부에서는 T[number] extends Falsy?false:true를 검사한 후 이 값이 true가 이 타입에 할당할 수 있으면 true, 아니면 false를 반환한다.
T의 값에 따른 T[number] extends Falsy?false:true의 타입에 대해 살펴보자
1) T에 falsy한 값들만 있을 경우
분배법칙에 의해 false|false|false....가 되어 false가 된다
2) T에 truthy한 값들만 있을 경우
분배법칙에 의해 true|true|true....가 되어 true가 된다
3) T에 두 값들이 섞여있을 경우
분배법칙에 의해 true|false|true|false....가 되어 boolean이 된다
우리가 true를 반환해야 하는 경우는 2)과 3)이다
이 타입을 기반으로 만들어진 구현이 2)과 3) 경우에 true를 반환하는지 확인하면 된다.
true는 1)의 경우를 확장한 타입이 아니므로, 1)의 경우일 때에는 최종적으로 false를 반환한다.
true는 2), 3)의 경우를 확장한 타입이므로 2), 3)의 경우일 때에는 최종적으로 true를 반환한다.
type AnyOf<T extends any[]> = T[number] extends 0 | '' | false | [] | {[key: string]: never}|null|undefined
? false : true;
이 풀이를 최근 추가된 테스트케이스에 맞게 변형한 코드이다.
애초에 T[number]가 Flasy를 확장하는지만 확인하면 되는 문제였다.
너무 어렵게 생각했던 것 같다
https://www.typescriptlang.org/ko/docs/handbook/type-compatibility.html
https://github.com/type-challenges/type-challenges/issues/954