如何更改索引表达式的类型?即: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
的键值。既然你提到你期望 k
是 keyof ILPAsset
,那意味着 c
应该是 ILPAsset
。所以签名应该是:
const checkText = (k: keyof ILPAsset, c: ILPAsset) => (textMatch(txt, c[k].toLowerCase()) ? c : null);
剩下的问题是现在索引访问 c[k]
将不是 string
类型,因为 ILPAsset
包含 number
和 string
键.
我们有两个解决方案。
我们可以检查 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
?
我的代码
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
的键值。既然你提到你期望 k
是 keyof ILPAsset
,那意味着 c
应该是 ILPAsset
。所以签名应该是:
const checkText = (k: keyof ILPAsset, c: ILPAsset) => (textMatch(txt, c[k].toLowerCase()) ? c : null);
剩下的问题是现在索引访问 c[k]
将不是 string
类型,因为 ILPAsset
包含 number
和 string
键.
我们有两个解决方案。
我们可以检查 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
?