如何更改索引表达式的类型?即:c [k]

时间:2018-09-25 20:48:10

标签: javascript typescript indexof keyof

我的代码

import * as R from 'ramda';

import { ILPAsset } from 'shared/types/models';

interface TextMatchFunction {
  (part: string, typed: string): boolean;
}

const textMatch: TextMatchFunction = (part: string, typed: string) => typed.search(part) !== -1;

export const filterAssets = (txt: string, assets: ILPAsset[]): ILPAsset[] => {
  const checkText = (k: string, c: keyof ILPAsset) => (textMatch(txt, c[k].toLowerCase()) ? c : null);
  const curriedCheckText = R.curry(checkText);
  // @ts-ignore
  const bySymbol = R.map(curriedCheckText('symbol'), assets);
  return R.reject(R.isNil, bySymbol);
};

IPAsset的界面

export interface ILPAsset {
  symbol: string;
  lastPayout: number;
  historical: number;
}

问题在这行上:

const checkText = (k: string, c: keyof ILPAsset) => (textMatch(txt, c[k].toLowerCase()) ? c : null);

Typescript期望k为数字c[k],而实际上它是ILPAsset中对象的键,在我的情况下,它是字符串,symbol

如何在Typescript中处理?

更新

更简单的方法是进行此操作,但是我对将来有关密钥检查的问题有了很好的回答:D

export const filterAssets = (typed: string, assets: ILPAsset[]): ILPAsset[] => {
  const checkSymbol = (asset: ILPAsset) => 
    asset.symbol.includes(typed.toUpperCase());
  return R.filter(checkSymbol, assets);
};

1 个答案:

答案 0 :(得分:1)

引起此问题的原因是您使用k作为c的密钥。既然您提到,您期望kkeyof ILPAsset,这意味着c应该是ILPAsset。所以签名应该是:

const checkText = (k: keyof ILPAsset, c: ILPAsset) => (textMatch(txt, c[k].toLowerCase()) ? c : null);

剩下的问题是,由于c[k]同时包含stringILPAsset键,因此索引访问number将不再是string类型。 / p>

为此,我们有两种解决方案。

我们可以检查c[k]是否为string,是否不返回null

const checkText = (k: keyof ILPAsset, c: ILPAsset)  => {
  const v = c[k];

  return typeof v === 'string' ? (textMatch(txt, v.toLowerCase()) ? c : null): null;
} 

我们还可以过滤键,因此k只能是键,而string

type StringKeys<T> = { [P in keyof T] : T[P] extends string ? P: never}[keyof T]
const checkText = (k: StringKeys<ILPAsset>, c: ILPAsset)  => (textMatch(txt, c[k].toLowerCase()) ? c : null);

注意string的唯一ILPAsset键是symbol,因此也许您应该完全评估对k参数的需求。为什么不只访问c.symbol