簡體   English   中英

打字稿在迭代器方法中提取精確的可區分條件聯合類型

[英]Typescript extract exact Discriminated conditional unions type in iterator method

export type FILTER_META =
  | {
      type: 'string';
      key: string;
      filters: { id: string; label?: string }[];
    }
  | {
      type: 'time';
      key: string;
      filters: { min: string; max: string  }[];
    }
  | {
      type: 'range';
      key: string;
      filters: { min: number; max: number }[];
    };

 type Unpacked<T> = T extends (infer U)[] ? U : T;
 type Foo = Unpacked<FILTER_META['filters']>;

// how to determine comparer type from meta object
// comparer:Foo doesn't work
// const comparator = <T extends FILTER_META, U extends Unpacked<T['filters']>>(

const comparator = (meta: FILTER_META, item: any, comparer: any) => {
  const DATE_PREFIX = '1/1/2022 ';

  switch (meta.type) {
    case 'string':
      return item?.[meta.key]?.toLowerCase() === comparer.id?.toLowerCase();
    case 'time': {
      const { min, max } = comparer;
      const compTime = new Date(DATE_PREFIX + item?.[meta.key]);
      return (
        new Date(DATE_PREFIX + min) <= compTime &&
        compTime <= new Date(DATE_PREFIX + max)
      );
    }
    case 'range': {
      const { min, max } = comparer;
      const compItem = item?.[meta.key];
      return min <= compItem && compItem <= max;
    }
  }
};


const genericFilter =
  (filterMeta: FILTER_META[]) =>
  (list = []) =>
    list.filter((item) =>
      filterMeta
        .filter((fMeta) => fMeta.filters.length)
        .every((meta) =>
          meta.filters.some((ft: any) => comparator(meta, item, ft))
        )
    );

以上是通用過濾器fn,它試圖根據過濾器類型過濾數組。 它提供了不同的過濾器數組,使用比較器 fn 過濾掉。

如何輸入第三個參數comparer:any來自FILTER_META類型的第一個參數

Stackblitz 鏈接https://stackblitz.com/edit/typescript-ku6bq7

switch(theValue)中的值必須與您要嵌套的變量相同(即theValue.filters.id )。 TypeScript 將知道當前theValue的過濾器是“字符串”類型而不是“時間”類型,只是因為switch(theValue.type) 沒有它, (即您當前的代碼)TypeScript 無法知道idcomparer中的鍵,因為它不知道comparer的類型是“字符串”、“時間”還是“范圍”。 這就是為什么comparer.id不是 TypeScript 有效的

例如,如果fo是明確的:(注意: .filters不是數組)

type fo =  {
  type: 'string';
  key: string;
  filters: { id: string; label?: string }; // not an array (is unpacked")
}
| {
  type: 'time';
  key: string;
  filters: { min: string; max: string }; // not an array (is "unpacked")
}
| {
  type: 'range';
  key: string;
  filters: { min: number; max: number }; // not an array (is "unpacked")
};

那么這個工作:

const comparator = (meta: FILTER_META, item: any, comparer: fo) => {
  const DATE_PREFIX = '1/1/2022 ';

  switch (comparer.type) {
    case 'string':
      return item?.[meta.key]?.toLowerCase() === comparer.filters.id?.toLowerCase();
    case 'time': {
      const { min, max } = comparer.filters;
      const compTime = new Date(DATE_PREFIX + item?.[meta.key]);
      return (
        new Date(DATE_PREFIX + min) <= compTime &&
        compTime <= new Date(DATE_PREFIX + max)
      );
    }
    case 'range': {
      const { min, max } = comparer.filters;
      const compItem = item?.[meta.key];
      return min <= compItem && compItem <= max;
    }
  }
};

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM