условные типы не исключаются из результата - PullRequest
0 голосов
/ 14 июля 2020

Я создал эту игровую площадку , которая иллюстрирует проблему, и вот код:

export enum TransformerActions {
  Delete = 'delete',
}

type FilteredKeys<T, U> = { [P in keyof T]: T[P] extends keyof TransformerActions ? never : T[P] extends U ? P : never }[keyof T];

type Fn = (...args: any[]) => any;

export type Transformed<S, M> = {
  [P in FilteredKeys<S, M>]: S[P] extends Fn ? ReturnType<S[P]> : never;
};


export const objectMapper = <S, M  extends Transformed<S, M>>(
    source: S,
    map: M
): Transformed<S, M> => { 
  const result: TransformerMap<S> = {};

  for (const k of Object.keys(source)) {
    if(!map[k]) {
      continue;
    }
    
    const value = source[k];

    if (map?.[k] === TransformerActions.Delete) {
      continue;
    }

    if (typeof map?.[k] === 'function') {
      result[k] = transform(map[k](source));;
      continue;
    }

    result[k] = value;
  }

  return result;
}

const source = {
    firstName: 'Paul',
    surname: 'Cowan',
    age: 50,
    address: 'somewhere in nowhere'
};

type Source = typeof source

const map = {
    address: TransformerActions.Delete,
    name: (n: Source) => `${n.firstName} ${n.surname}`
}

const result = objectMapper(source, map)

/* should be 
{
  name: string
}

I don't think filtering on enum is possible but not sure why the ReturnType is not working
*/

В основном у меня есть функция objectTransformer, и я хочу использовать условные типы для фильтрации из всех полей, возвращающих специфицированное c перечисление, или если поле является функцией, то я хочу, чтобы это поле возвращало ReturnType функции, а не саму функцию

const map = {
    address: TransformerActions.Delete,
    name: (n: Source) => `${n.firstName} ${n.surname}`
}

Ни одно из условий не работает для меня прямо сейчас :).

1 Ответ

1 голос
/ 15 июля 2020

Надеюсь, вы это имеете в виду, я до сих пор не понимаю, зачем вам TransformerActions.Delete, если просто исключение ключа из объекта карты дает тот же результат ... но я думаю, у вас может быть спецификация c вариант использования, и вы пытались привести здесь пример. Опять же, надеюсь, это именно то, что вы имели в виду -

export enum TransformerActions {
  Delete = 'delete',
}

 /** takes an type like {foo: number, bar: never} returns type {foo: number}  */
type RemoveNever<T> = Pick<T, { [K in keyof T]: T[K] extends never ? never : K }[keyof T]>;

type Fn<T> = (arg: T) => any; 
type ObjectMap<S> = Record<string, Fn<S> | TransformerActions> 

type Transformed_Stage1<S, M extends ObjectMap<S>> = {
  [P in keyof M]: M[P] extends Fn<S> ?
    ReturnType<M[P]> :
    M[P] extends TransformerActions.Delete ?
      never :
      never;
}

/** split Transformed just for clarity sake, you can probably write this in one type decleration */
export type Transformed<S, M extends ObjectMap<S>> = RemoveNever<Transformed_Stage1<S, M>>;


export const objectMapper = <S, M  extends ObjectMap<S>>(
    source: S,
    map: M
): Transformed<S, M> => { 
    return {} as  Transformed<S, M>
}

const source = {
    firstName: 'Paul',
    surname: 'Cowan',
    age: 50,
    address: 'somewhere in nowhere'
};

type Source = typeof source

const map = {
    address: TransformerActions.Delete,
    name: (n: Source) => `${n.firstName} ${n.surname}`
}

const result = objectMapper(source, map);

/* only result.name autocompletes */
result.name
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...