[TECH-QA] TypeScript๋กœ ๊น”๋”ํ•œ ์ฟผ๋ฆฌ ๋ฌธ์ž์—ด ๋งŒ๋“ค๊ธฐ: Record<string, never> ํ™œ์šฉ๋ฒ•

๐Ÿšฉ Record<string, never> ํ™œ์šฉ๋ฒ•

import { isNil, isArray, isEmpty } from 'lodash';
import qs from 'query-string';

const buildQueryString = <T = Record<string, never>>(params?: T): string => {
  // ์œ ํšจํ•˜์ง€ ์•Š์€ ๊ฐ’(null, undefined, ๋นˆ ๋ฌธ์ž์—ด/๋ฐฐ์—ด) ์ œ๊ฑฐ
  const cleanedParams = omitBy(params || {}, (val) => {
    if (isNil(val)) return true;
    return isArray(val) && (val as string[]).every((v) => !v);
  });

  // ๊ฐ์ฒด๊ฐ€ ๋น„์–ด ์žˆ์œผ๋ฉด ๋นˆ ๋ฌธ์ž์—ด ๋ฐ˜ํ™˜, ์•„๋‹ˆ๋ฉด ์ฟผ๋ฆฌ ๋ฌธ์ž์—ด ์ƒ์„ฑ
  return isEmpty(cleanedParams) ? '' : `?${qs.stringify(cleanedParams, { arrayFormat: 'comma', encode: false })}`;
};

// ์‚ฌ์šฉ ์˜ˆ์ œ
console.log(buildQueryString()); // ''
console.log(buildQueryString({ name: 'John', age: '25', empty: '' })); // '?name=John,age=25'
console.log(buildQueryString({ items: [], invalid: null })); // ''
console.log(buildQueryString({ tags: ['red', 'blue'], empty: null })); // '?tags=red,blue'
buildQueryString ํ•จ์ˆ˜๋Š” ํ”„๋ก ํŠธ์—”๋“œ์—์„œ API ์š”์ฒญ์„ ์œ„ํ•œ ์ฟผ๋ฆฌ ๋ฌธ์ž์—ด์„ ์ƒ์„ฑํ•˜๋Š” ์œ ํ‹ธ๋ฆฌํ‹ฐ ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. ์ž…๋ ฅ ๊ฐ์ฒด์—์„œ ์œ ํšจํ•˜์ง€ ์•Š์€ ๊ฐ’(null, undefined, ๋นˆ ๋ฌธ์ž์—ด, ๋นˆ ๋ฐฐ์—ด ๋˜๋Š” ๋ชจ๋“  ์š”์†Œ๊ฐ€ ๋นˆ ๊ฐ’์ธ ๋ฐฐ์—ด)์„ ์ œ๊ฑฐํ•˜๊ณ , ์œ ํšจํ•œ ๋ฐ์ดํ„ฐ๋งŒ ํฌํ•จํ•œ ์ฟผ๋ฆฌ ๋ฌธ์ž์—ด์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” API ์š”์ฒญ์„ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ๋งŒ๋“ค๊ณ , ์„œ๋ฒ„์˜ ์ฒ˜๋ฆฌ ๋ถ€๋‹ด์„ ์ค„์ด๋ฉฐ, ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์„ ๊ฐœ์„ ํ•˜๋Š” ๋ฐ ๊ธฐ์—ฌํ•ฉ๋‹ˆ๋‹ค.

ํ•จ์ˆ˜ ๊ตฌ์กฐ

์ œ๋„ค๋ฆญ ํƒ€์ž…

<T = Record<stringุŒ never>>

T๋Š” ์ž…๋ ฅ ํŒŒ๋ผ๋ฏธํ„ฐ params์˜ ํƒ€์ž…์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. ๊ธฐ๋ณธ ํƒ€์ž… Record๋Š” ์†์„ฑ์ด ์—†๋Š” ๋นˆ ๊ฐ์ฒด {}๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. params๊ฐ€ undefined์ด๊ฑฐ๋‚˜ ์ „๋‹ฌ๋˜์ง€ ์•Š์„ ๊ฒฝ์šฐ, ๋นˆ ๊ฐ์ฒด {}๋กœ ์ฒ˜๋ฆฌ๋˜์–ด ํ•จ์ˆ˜๊ฐ€ ์•ˆ์ „ํ•˜๊ฒŒ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

ํŒŒ๋ผ๋ฏธํ„ฐ

params?: T

  • params๋Š” ์„ ํƒ์ ์ด๋ฉฐ, ๊ฐ์ฒด ํ˜•ํƒœ๋กœ ์ „๋‹ฌ๋ฉ๋‹ˆ๋‹ค.
  • params || {}๋ฅผ ํ†ตํ•ด undefined์ผ ๊ฒฝ์šฐ ๋นˆ ๊ฐ์ฒด๋กœ ๋Œ€์ฒด๋ฉ๋‹ˆ๋‹ค.

๋กœ์ง

Lodash์˜ omitBy

Lodash์˜ omitBy๋ฅผ ์‚ฌ์šฉํ•ด null, undefined, ๋นˆ ๋ฌธ์ž์—ด ๋˜๋Š” ๋ชจ๋“  ์š”์†Œ๊ฐ€ ๋นˆ ๊ฐ’์ธ ๋ฐฐ์—ด์„ ์ œ๊ฑฐ.
{ name: "John", empty: null, items: [""] } โ†’ { name: "John" }.
  • Lodash์˜ isEmpty๋กœ ์ •๋ฆฌ๋œ ๊ฐ์ฒด๊ฐ€ ๋น„์–ด ์žˆ๋Š”์ง€ ํ™•์ธ.
  • ๋น„์–ด ์žˆ์œผ๋ฉด ' '๋ฅผ ๋ฐ˜ํ™˜.
  • ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด qs.stringify๋ฅผ ์‚ฌ์šฉํ•ด ์ฟผ๋ฆฌ ๋ฌธ์ž์—ด๋กœ ๋ณ€ํ™˜ํ•˜๊ณ , ?๋ฅผ ์ ‘๋‘์‚ฌ๋กœ ์ถ”๊ฐ€.
  • arrayFormat: 'comma'๋Š” ๋ฐฐ์—ด์„ ์‰ผํ‘œ๋กœ ๊ตฌ๋ถ„ (์˜ˆ: tags=red,blue).
  • encode: false๋Š” URL ์ธ์ฝ”๋”ฉ์„ ๋น„ํ™œ์„ฑํ™”ํ•ด ๊ฐ€๋…์„ฑ์„ ๋†’์ž„.

๐Ÿ“ ์ž…๋ ฅ ์—†์Œ

buildQueryString(); // ์ถœ๋ ฅ: ''
  • params๊ฐ€ undefined์ด๋ฏ€๋กœ ๋นˆ ๊ฐ์ฒด {}๋กœ ์ฒ˜๋ฆฌ.
  • omitBy({}, ...)๋Š” ๋นˆ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜, isEmpty๊ฐ€ true์ด๋ฏ€๋กœ '' ๋ฐ˜ํ™˜.

๐Ÿ“ ์œ ํšจํ•œ ๊ฐ’ ํฌํ•จ

buildQueryString({ name: 'John', age: '25', empty: '' }); // ์ถœ๋ ฅ: '?name=John,age=25'
  • empty: ''๋Š” ์ œ๊ฑฐ๋จ.
  • cleanedParams = { name: 'John', age: '25' }.
  • qs.stringify๋กœ name=John,age=25๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ?๋ฅผ ์ถ”๊ฐ€.

๐Ÿ“ ์œ ํšจํ•˜์ง€ ์•Š์€ ๊ฐ’๋งŒ ํฌํ•จ

buildQueryString({ items: [], invalid: null }); // ์ถœ๋ ฅ: ''
  • items: []์™€ invalid: null์€ ์ œ๊ฑฐ๋จ.
  • cleanedParams = {}, isEmpty๊ฐ€ true์ด๋ฏ€๋กœ '' ๋ฐ˜ํ™˜.

๐Ÿ“ ๋ฐฐ์—ด ํฌํ•จ

buildQueryString({ tags: ['red', 'blue'], empty: null }); // ์ถœ๋ ฅ: '?tags=red,blue'
  • empty: null์€ ์ œ๊ฑฐ๋จ.
  • cleanedParams = { tags: ['red', 'blue'] }.
  • qs.stringify๋กœ tags=red,blue๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ?๋ฅผ ์ถ”๊ฐ€.

๋ฐฐ์—ด ํฌํ•จ

  • ํšจ์œจ์ ์ธ ์š”์ฒญ: ๋ถˆํ•„์š”ํ•œ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ œ๊ฑฐํ•ด ๋„คํŠธ์›Œํฌ ์š”์ฒญ ํฌ๊ธฐ๋ฅผ ์ค„์ด๊ณ , ์„œ๋ฒ„์˜ ์ฒ˜๋ฆฌ ๋ถ€๋‹ด์„ ์™„ํ™”.
  • ํƒ€์ž… ์•ˆ์ „์„ฑ: Record๋ฅผ ๊ธฐ๋ณธ ํƒ€์ž…์œผ๋กœ ์‚ฌ์šฉํ•ด ์ž…๋ ฅ์ด ์—†๊ฑฐ๋‚˜ ๋นˆ ๊ฐ์ฒด์ผ ๋•Œ๋„ ์•ˆ์ „ํ•˜๊ฒŒ ์ฒ˜๋ฆฌ.
  • ์‚ฌ์šฉ์ž ๊ฒฝํ—˜: ๊ฐ„๊ฒฐํ•œ ์ฟผ๋ฆฌ ๋ฌธ์ž์—ด์€ URL์„ ๊น”๋”ํ•˜๊ฒŒ ์œ ์ง€ํ•˜๋ฉฐ, ๋ธŒ๋ผ์šฐ์ € ํžˆ์Šคํ† ๋ฆฌ๋‚˜ ๊ณต์œ  ๋งํฌ์˜ ๊ฐ€๋…์„ฑ์„ ๋†’์ž„.
  • ์„œ๋ฒ„ ๋ถ€ํ•˜ ๊ฐ์†Œ: ์œ ํšจํ•œ ๋ฐ์ดํ„ฐ๋งŒ ์„œ๋ฒ„๋กœ ์ „์†ก๋˜๋ฏ€๋กœ ์„œ๋ฒ„์˜ ๊ฒ€์ฆ ๋กœ์ง์ด ๊ฐ„์†Œํ™”๋จ.

ํŠธ๋ž˜ํ”ฝ ๊ด€๋ฆฌ์™€์˜ ์—ฐ๊ด€์„ฑ

  • ํ”„๋ก ํŠธ์—”๋“œ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ •๋ฆฌํ•˜๋ฉด ๋ถˆํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ ์ „์†ก์ด ์ค„์–ด๋“ค์–ด ๋„คํŠธ์›Œํฌ ํŠธ๋ž˜ํ”ฝ์ด ๊ฐ์†Œ.
  • ์„œ๋ฒ„๋Š” ์œ ํšจํ•œ ๋ฐ์ดํ„ฐ๋งŒ ์ฒ˜๋ฆฌํ•˜๋ฏ€๋กœ CPU/๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์ด ์ค„๊ณ , ์บ์‹ฑ ํšจ์œจ์„ฑ์ด ํ–ฅ์ƒ.
  • ์ด๋Š” ํŠธ๋ž˜ํ”ฝ ์ŠคํŒŒ์ดํฌ๋ฅผ ๊ฐ„์ ‘์ ์œผ๋กœ ๋ฐฉ์ง€ํ•˜๋ฉฐ, ์ „์ฒด ์‹œ์Šคํ…œ ์„ฑ๋Šฅ์„ ์ตœ์ ํ™”.