idx: The Existential Function
페이스북에서는 GraphQL로 가져온 데이터 구조에서 깊게 중첩된 값에 접근해야 하는 경우가 많다. 이러한 깊게 중첩된 값에 접근하는 과정에서 하나 이상의 중간 필드가 nullable인 경우가 흔하다. 중간 필드가 null이 될 수 있는 이유는 다양하다. 실패한 개인정보 확인부터, 치명적이지 않은 오류를 표현하는 가장 유연한 방법으로 null을 사용하는 경우까지 여러 가지가 있다.
안타깝게도, 깊게 중첩된 값에 접근하는 작업은 현재 매우 번거롭고 장황하다.
props.user &&
props.user.friends &&
props.user.friends[0] &&
props.user.friends[0].friends;
ECMAScript에 존재 여부를 확인하는 연산자를 도입하는 제안이 있어 이를 훨씬 편리하게 만들 수 있다. 하지만 이 제안이 확정되기 전까지, 우리는 삶의 질을 개선하고 기존 언어의 의미를 유지하며 Flow를 통한 타입 안전성을 장려하는 해결책을 원했다.
그래서 우리는 idx
라는 존재 여부를 확인하는 _함수_를 만들었다.
idx(props, _ => _.user.friends[0].friends);
이 코드 스니펫의 호출은 위의 불리언 표현식과 유사하게 동작하지만, 반복이 훨씬 적다. idx
함수는 정확히 두 개의 인자를 받는다:
- 일반적으로 중첩된 값에 접근하려는 객체나 배열 등의 값.
- 첫 번째 인자를 받아 그 위에서 중첩된 값에 접근하는 함수.
이론적으로, idx
함수는 null이나 undefined에 접근할 때 발생하는 오류를 try-catch로 잡으려고 시도한다. 이런 오류가 잡히면 null이나 undefined를 반환한다. (이 구현 방법은 idx.js에서 확인할 수 있다.)
실제로, 모든 중첩된 속성 접근을 try-catch로 감싸는 것은 느리고, 특정 종류의 TypeError를 구분하는 것은 취약하다. 이러한 단점을 해결하기 위해, 우리는 위의 idx
호출을 다음 표현식으로 변환하는 Babel 플러그인을 만들었다:
props.user == null
? props.user
: props.user.friends == null
? props.user.friends
: props.user.friends[0] == null
? props.user.friends[0]
: props.user.friends[0].friends;
마지막으로, 우리는 idx
에 대한 커스텀 Flow 타입 선언을 추가했다. 이를 통해 두 번째 인자에서의 탐색이 적절히 타입 체크되면서도 nullable 속성에 대한 중첩 접근이 허용된다.
이 함수, Babel 플러그인, 그리고 Flow 선언은 이제 GitHub에서 사용할 수 있다. idx와 babel-plugin-idx npm 패키지를 설치하고 .babelrc
파일의 플러그인 목록에 "idx"를 추가하면 사용할 수 있다.