typescript - eroare: Proprietatea 'toLowerCase' nu există pe tipul 'NonNullable'.ts(2339)


Am definit o metodă numită filterByFront

export const filterByFront = <T>(
  value: string,
  jsonData: T[],
  setData: (data: T[]) => void,
  filterKey: keyof T
) => {
  const originData = jsonData;
  if (!!value && !!value.trim()) {
    setData(originData);
  } else {
    const filterData = originData.filter((item) => {
      const newFilterValue = item[filterKey];
      return newFilterValue
        ?.toLowerCase()    //error message shows in this line 
        ?.includes(value.trim().toLowerCase());
    });

    setData(filterData);
  }
};

și l-am apelat în componente astfel

   <Input.Search
            key="filter_role"
            placeholder={t('common.filter')}
            onSearch={(value) =>
              filterByFront<IRoleListItem>(value, jsonData, setRoleData, 'id')
            }
          />,

definiția tipului

export interface IRoleListItem {
  authority?: string;

  id?: string;

  privilege?: string;

  prohibit?: string;

  tag_list?: string;
}

arată eroare :

Proprietatea 'toLowerCase' nu există pe tipul 'NonNullable'.ts(2339)

Cum pot face ca această eroare să dispară

Răspuns #1

Vă rugăm să folosiți această restricție T extends Record<PropertyKey, { toLowerCase:() => string }>:

export const filterByFront = <T extends Record<PropertyKey, { toLowerCase: () => string }>>(
  value: string,
  jsonData: T[],
  filterKey: keyof T
) => {
  const originData = jsonData;
  if (!!value && !!value.trim()) {
    console.log(originData);
  } else {
    const filterData = originData.filter((item) => {
      const newFilterValue = item[filterKey];
      return newFilterValue
        ?.toLowerCase()
        ?.includes(value.trim().toLowerCase());
    });

    console.log(filterData);
  }
};

Teren de joacă

Răspunsul #2

Esența problemei este că T nu are constrângeri, așa că nu putem presupune că va avea o proprietate numită toLowerCase. Așa cum menționează captain-yossarian în comentariile lor la răspuns, tipurile create cu type au o semnătură de index implicită, în timp ce tipurile create cu interface nu au. Dacă poți defini tipul elementului tău de listă de rol folosind type, soluția lor ar trebui să funcționeze. Dacă nu, ar putea fi necesar să faci o verificare la runtime pentru a vedea dacă T este un șir înainte de a putea să îl tratezi ca atare:

export interface IRoleListItem {
  authority?: string;
  id?: string;
  privilege?: string;
  prohibit?: string;
  tag_list?: string;
}

export const filterByFront = <T, K extends keyof T>(
  value: string,
  jsonData: T[],
  setData: (data: T[]) => void,
  filterKey: K
) => {
  const originData = jsonData;
  if (!!value && !!value.trim()) {
    setData(originData);
  } else {
    const filterData = originData.filter((item) => {
      const newFilterValue = item[filterKey];

      if (typeof newFilterValue === "string") {
        return newFilterValue?.toLowerCase()?.includes(value.trim().toLowerCase());
      } else {
        return false;
      }
    });

    setData(filterData);
  }
};

declare const value: string;
declare const jsonData: IRoleListItem[];
declare const setRoleData: (data: IRoleListItem[]) => {};

filterByFront(value, jsonData, setRoleData, 'id');

Teren de joacă TS