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

How to change type of index expression? ie: c[k]

我的代码

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);
};

问题是因为您正在使用k作为c的键值。既然你提到你期望 kkeyof ILPAsset,那意味着 c 应该是 ILPAsset。所以签名应该是:

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

剩下的问题是现在索引访问 c[k] 将不是 string 类型,因为 ILPAsset 包含 numberstring 键.

我们有两个解决方案。

我们可以检查 c[k] 是否是 string 如果不是 return 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);

注意ILPAsset 的唯一 string 键是 symbol 所以也许你应该评估对 [=13= 的需求] 参数。为什么不直接访问 c.symbol