bospur
@bospur
Frontend dev

Как правильно типизировать функцию getvalue?

Есть вот такая задача:
Типизация функции getValue
Необходимо типизировать функцию, реализация которой предоставлена ниже:

const getValue =
  (obj, isIncludeKey = false) =>
  (key) => {
    if (!isIncludeKey) {
      return obj[key];
    }

    return Object.entries(obj).reduce((result, pair) => {
      const [pairKey, pairValue] = pair;

      if (pairKey.includes(key)) {
        return [...result, pairValue];
      }

      return result;
    }, []);
  };

Требования:

Key должен быть типизирован, то есть нельзя указать key, который не принадлежит объекту
Возвращаемое значение (одиночное значение или массив) должно на уровне типов конкретизироваться через параметр isIncludeKey (подсказка, необходимо использовать Generic и conditional type)

у меня не получается использовать conditional type, получилось что то похожее с ипользованиеv type guard, но это не совсем то, т.к. при поиске по похожим ключам возвращается never[] а хотелось бы что бы правильный тип

Вот что примерно выходит когда я пробую:
const checkIsIncludeKey = (isIncludeKey: boolean): isIncludeKey is true => {
    return isIncludeKey;
  };

  const getValue =
    <T extends Object, V extends boolean = false>(obj: T, isIncludeKey: V) =>
    (key: keyof T) => {
      if (!checkIsIncludeKey(isIncludeKey)) {
        return obj[key];
      }

      return Object.entries(obj).reduce((result, pair) => {
        const [pairKey, pairValue] = pair;

        if (pairKey.includes(key as string)) {
          return [...result, pairValue];
        }

        return result;
      }, []);
    };

  const a = getValue({ a: 123, cfd: "123123" }, true)("cf");
  • Вопрос задан
  • 83 просмотра
Пригласить эксперта
Ответы на вопрос 1
WblCHA
@WblCHA
https://www.typescriptlang.org/play/?#code/MYewdgz...

const error = Symbol();
type CheckSubKey<K, SK extends string> = K extends `${string}${SK}${string}`
  ? SK
  : SK & { [error]: '(!) Invalid subkey (!)' };

interface GetValue {
  <T extends object>(obj: T): <K extends keyof T>(key: K) => T[K];
  <T extends object, I extends boolean = false>(
    obj: T,
    isIncludeKey?: I,
  ): I extends true
    ? <K extends string>(key: CheckSubKey<keyof T, K>) => T[`${string}${K}${string}` & keyof T][]
    : <K extends keyof T>(key: K) => T[K];
}

const getValue: GetValue =
  (obj: object, isIncludeKey = false) =>
  (key: unknown): unknown[] => {
    if (!isIncludeKey) {
      return obj[key as keyof typeof obj];
    }

    return Object.entries(obj).reduce((result: unknown[], pair: [key: string, value: unknown]) => {
      const [pairKey, pairValue] = pair;

      if (pairKey.includes(key as string)) {
        return [...result, pairValue];
      }

      return result;
    }, []);
  };

const o = {
  asd: 1 as const,
  asdfg: '2' as const,
  qweg: [3] as const,
};

const v1 = getValue(o)('asd'); // 1
const v2 = getValue(o, true)('a'); // (1 | "2")[]
const v3 = getValue(o, true)('f'); // "2"[]
const v4 = getValue(o, true)('g'); // ("2" | readonly [3])[]
const v5 = getValue(o, true)('uuu'); // error
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы