Typescript에서 Predicate Combinator 사용

19918 단어 typescript

문제:



술어 함수가 너무 많이 확인하고 있으며 다음보다 더 많은 일을 담당하고 있습니다.

enum UserRole {
  Administrator = 1,
  Editor = 2,
  Subscriber = 3,
  Writer = 4,
}

interface User {
  username: string;
  age: number;
  role: UserRole;
}

const users = [
  { username: "John", age: 25, role: UserRole.Administrator },
  { username: "Jane", age: 7, role: UserRole.Subscriber },
  { username: "Liza", age: 18, role: UserRole.Writer },
  { username: "Jim", age: 16, role: UserRole.Editor },
  { username: "Bill", age: 32, role: UserRole.Editor },
];

const greaterThen17AndWriterOrEditor = users.filter((user: User) => {
  return (
    user.age > 17 &&
    (user.role === UserRole.Writer || user.role === UserRole.Editor)
  );
});

const greaterThen5AndSubscriberOrWriter = users.filter((user: User) => {
    return user.age > 5 && user.role === UserRole.Writer;
});


해결책:



술어 결합자를 사용하기 시작해야 합니다. 코드 가독성과 재사용 가능성이 높아집니다.

type PredicateFn = (value: any, index?: number) => boolean;
type ProjectionFn = (value: any, index?: number) => any;

function or(...predicates: PredicateFn[]): PredicateFn {
  return (value) => predicates.some((predicate) => predicate(value));
}

function and(...predicates: PredicateFn[]): PredicateFn {
  return (value) => predicates.every((predicate) => predicate(value));
}

function not(...predicates: PredicateFn[]): PredicateFn {
  return (value) => predicates.every((predicate) => !predicate(value));
}


조합하여 사용하실 수 있습니다.

const isWriter = (user: User) => user.role === UserRole.Writer;
const isEditor = (user: User) => user.role === UserRole.Editor;
const isGreaterThan17 = (user: User) => user.age > 17;
const isGreaterThan5 = (user: User) => user.age > 5;

const greaterThan17AndWriterOrEditor = users.filter(
    and(isGreaterThan17, or(isWriter, isEditor))
);

const greaterThan5AndSubscriberOrWriter = users.filter(
    and(isGreaterThan5, isWriter)
);


공장과 더 나은 조건자 결합자



술어 결합자는 너무 많은 변수를 생성하므로 이러한 기능 사이에서 길을 잃기 쉽습니다. 콤비네이터 조건자 함수를 한 번만 사용한다면 좀 더 일반적인 것을 사용하는 것이 좋습니다.

const isWriter = (user: User) => user.role === UserRole.Writer;
const isEditor = (user: User) => user.role === UserRole.Editor;
const isGreaterThan17 = (user: User) => user.age > 17;
const isGreaterThan5 = (user: User) => user.age > 5;

const greaterThan17AndWriterOrEditor = users.filter(
    and(isGreaterThan17, or(isWriter, isEditor))
);

const greaterThan5AndSubscriberOrWriter = users.filter(
    and(isGreaterThan5, isWriter)
);


결합자 술어 팩토리를 사용하여 이 문제를 해결할 수 있습니다.

const isRole = (role: UserRole) => 
    (user: User) => user.role === role;

const isGreaterThan = (age: number) =>
    (user: User) => user.age > age;


const greaterThan17AndWriterOrEditor = users.filter(
    and(isGreaterThan(17), or(isRole(UserRole.Writer), isRole(UserRole.Editor)))
);

const greaterThan5AndSubscriberOrWriter = users.filter(
    and(isGreaterThan(5), isRole(UserRole.Writer))


일부 함수 호출이 동일한 인수로 반복되는 것을 알아차렸을 것입니다. 가장 좋은 옵션은 결합기 술어와 함께 술어 팩토리를 혼합하는 것입니다. 따라서 우리는 두 세계의 장점을 모두 누릴 수 있습니다.

const isRole = (role: UserRole) => 
    (user: User) => user.role === role;

const isGreaterThan = (age: number) =>
    (user: User) => user.age > age;

const isWriter = isRole(UserRole.Writer)

const greaterThan17AndWriterOrEditor = users.filter(
    and(isGreaterThan(17), or(isWriter, isRole(UserRole.Editor)))
);

const greaterThan5AndSubscriberOrWriter = users.filter(
    and(isGreaterThan(5), isWriter)
);


이런 식으로 반복 횟수를 줄이고 코드를 깨끗하고 깔끔하게 유지합니다.

좋은 웹페이지 즐겨찾기