본문 바로가기

TypeScript/실험실

타입스크립트 keyof, Record

React Native로 권한을 제공해야 하는 커스텀 훅을 만들기 위해서 작업을 하는 도중 타입을 선언하는 과정에서 

새로운 경험을 하게 되었다. 

import {
  checkMultiple,
  PERMISSIONS,
  PermissionStatus,
  requestMultiple,
  RESULTS,
} from 'react-native-permissions';
import usePlatform from './usePlatform';
import {useEffect} from 'react';

type AndroidPermissions =
  (typeof PERMISSIONS.ANDROID)[keyof typeof PERMISSIONS.ANDROID];
type IOSPermissions = (typeof PERMISSIONS.IOS)[keyof typeof PERMISSIONS.IOS];

interface Permissions {
  android: AndroidPermissions[];
  ios: IOSPermissions[];
}

const usePermission = (permissions: Permissions) => {
  const {isIOS} = usePlatform();
  const platformPermissions = isIOS ? permissions.ios : permissions.android;

  const checkGranted = (
    statuses: Record<AndroidPermissions | IOSPermissions, PermissionStatus>,
  ) => {
    return platformPermissions.every(
      permission => statuses[permission] === RESULTS.GRANTED,
    );
  };

  const requestPermission = async () => {
    const statuses = await checkMultiple(platformPermissions);

    if (checkGranted(statuses)) {
      // 권한 존재
    } else {
      const requestStatuses = await requestMultiple(platformPermissions);

      if (checkGranted(requestStatuses)) {
        // 권한 승인
      } else {
        // 권한 존재 X
      }
    }
  };

  useEffect(() => {
    requestPermission;
  }, []);
};

export default usePermission;

전체적인 코드는 이렇게 구성되어 있는데, 아직 작업 중인 코드라서 완성도는 낮다... 

해당 경험을 하고 호다닥 작성하고 싶어서 메모를 남기고 글을 작성하는 중

 

keyof

import {
  checkMultiple,
  PERMISSIONS,
  PermissionStatus,
  requestMultiple,
  RESULTS,
} from 'react-native-permissions';

// ...
type AndroidPermissions =
  (typeof PERMISSIONS.ANDROID)[keyof typeof PERMISSIONS.ANDROID];
type IOSPermissions = (typeof PERMISSIONS.IOS)[keyof typeof PERMISSIONS.IOS];

interface Permissions {
  android: AndroidPermissions[];
  ios: IOSPermissions[];
}

react-native-permissions 패키지를 사용하는데, 매개변수로 넘겨받는 값이 PERMISSIONS 객체의 value로 구성된 배열이다. 

types를 제공하는지 찾아봤는데 따로 types는 제공하지 않는 것 같아서 어떤 방법을 사용해야하나 고민을 하고 있었는데, keyof라는 키워드를 사용하면 객체의 키값을 받아올 수 있었다. 

 

type AndroidPermissions =
  (typeof PERMISSIONS.ANDROID)[keyof typeof PERMISSIONS.ANDROID];

이걸로 PERMISSIONS.ANDROID의 타입에게 동일한 타입의 kay값으로 value를 추출할 수 있다는 것을 알았다. 

 

{
  ACCEPT_HANDOVER: 'android.permission.ACCEPT_HANDOVER';
  ACCESS_BACKGROUND_LOCATION: 'android.permission.ACCESS_BACKGROUND_LOCATION';
  ACCESS_COARSE_LOCATION: 'android.permission.ACCESS_COARSE_LOCATION';
  ACCESS_FINE_LOCATION: 'android.permission.ACCESS_FINE_LOCATION';
}

다음과 같은 값이 PERMISSION.ANDROID의 타입이라고 생각해보자. 

여기서 keyof typeof pERMISSIONS.ANDROID는 다음과 같다. 

 

'ACCEPT_HANDOVER' | 'ACCESS_BACKGROUND_LOCATION' | 'ACCESS_COARSE_LOCATION' | 'ACCESS_FINE_LOCATION'

이렇게 구성된 값을 (typeof PERMISSIONS.ANDROID)[keyof typeof PERMISSIONS.ANDROID] 이렇게 사용한다면

객체의 value만 뚝하고 나오게 되는 것이다. 

 

'android.permission.ACCEPT_HANDOVER' | 'android.permission.ACCESS_BACKGROUND_LOCATION' | 'android.permission.ACCESS_COARSE_LOCATION' | 'android.permission.ACCESS_FINE_LOCATION'

객체의 value를 가지고 오는 방식이 조금 더 까다롭긴 하지만 불가능한 것이 아니며 자주 사용될 방법이라고 생각한다. 

 

Record

const checkGranted = (
    statuses: Record<AndroidPermissions | IOSPermissions, PermissionStatus>,
  ) => {
    return platformPermissions.every(
      permission => statuses[permission] === RESULTS.GRANTED,
    );
  };

앞서 만든 Permissions들을 key값으로 가지고 있지만 value는 새롭게 구성된 값으로 만들어질 때 사용할 수 있는 것이 Record이다. 

 

Record<K, V>

키가 K 타입이고 값은 V로 구성되는 타입을 만들어주는 유틸 타입이다. 

객체 형식으로 인터페이스를 만들어서 타입을 지정해줄 수 있지만 Record를 사용하면 간단해서 동일한 기능을 구현할 수 있기 때문에 사용하면 개발의 질이 올라갈 것 같다. 

반응형

'TypeScript > 실험실' 카테고리의 다른 글

[TypeScript] Webpack 환경에서 TypeScript 사용하기  (0) 2022.10.02