打字稿:如何键入 Ramda R.prop(key) T' 不可分配给 '(s: {}) => {} 类型的参数
Typescript: How to type Ramda R.prop(key) T' is not assignable to parameter of type '(s: {}) => {}
打字稿错误
(method) R.Static.prop(p: string): (obj: Record) => T (+3 overloads)
Returns a function that when supplied an object returns the indicated property of that object, if it exists.
Argument of type '(obj: Record) => T' is not assignable to parameter of type '(s: {}) => {}'.
Types of parameters 'obj' and 's' are incompatible.
Type '{}' is not assignable to type 'Record'.
Index signature is missing in type '{}'.ts(2345)
代码:
https://ramdajs.com/docs/#lens
// Changes value of key in object without mutation
export const updateKey = (key: string) => R.lens(R.prop(key), R.assoc(key));
如何使用此功能
interface IMyObj {
position: number;
price: number;
value: number;
}
const myObj: IMyObj = {
position: 1,
price: 100,
value: 100
}
const updateKey = (key: string) => R.lens(R.prop(key), R.assoc(key));
const newObj = R.set(updateKey('value'), 200, myObj);
console.log('newObj', newObj); // {"position":1,"price":100,"value":200}
在我的实际应用中,我的 IAsset 对象的签名如下所示:
export interface IAsset {
[key: string]: string | number | undefined | boolean;
availableSupply?: string;
currency: string;
exchange: string;
exchange_base?: string;
marketCap: number;
name: string;
percentage?: number;
price: number;
position?: number;
value?: number;
inWatchlist?: boolean;
}
// Changes value of key in object without mutation
export const updateKey = (key: IAsset[string]) => {
if (key) {
return R.lens(R.prop(key), R.assoc(key));
}
}
但是它仍然产生这个 Typescript 警告:
Argument of type '(obj: Record) => T' is not assignable to parameter of type '(s: {}) => {}'.
Types of parameters 'obj' and 's' are incompatible.
Type '{}' is not assignable to type 'Record'.
Index signature is missing in type '{}'.ts(2345)
另请注意,Typescript 正在扼杀漂亮的小型 1 行 Ramda 函数的乐趣。
对于你原来的问题:
我不是 Ramda 方面的专家,所以也许我遗漏了一些有关如何使用这些类型的信息,但看起来您可以通过使 updateKey
通用来消除类型错误:
const updateKey = <T, K extends string>(key: K) => R.lens(R.prop<K, T>(key), R.assoc(key));
请注意,此处的类型推断不会很好。如果将鼠标悬停在 updateKey("value")
上,推断类型将为 <{}, "value">(key: "value") => Lens
,因此在某些情况下您可能需要明确指定类型参数。
对于您更新的问题:
我肯定缺少某些东西。 IAsset
的界面不支持数字键——仅支持字符串。所以 应该 除了字符串之外不需要担心任何其他事情,但是,为了论证,我们假设您还想处理数字或符号键。
如果你看@types/ramda
,prop
and assoc
的单参数重载只接受字符串:
/**
* Returns a function that when supplied an object returns the indicated property of that object, if it exists.
*/
prop<T>(__: Placeholder, obj: T): <P extends keyof T>(p: P) => T[P];
prop<P extends keyof T, T>(p: P, obj: T): T[P];
prop<P extends string>(p: P): <T>(obj: Record<P, T>) => T;
prop<P extends string, T>(p: P): (obj: Record<P, T>) => T;
/**
* Makes a shallow clone of an object, setting or overriding the specified property with the given value.
*/
assoc<T, U>(__: Placeholder, val: T, obj: U): <K extends string>(prop: K) => Record<K, T> & U;
assoc<U, K extends string>(prop: K, __: Placeholder, obj: U): <T>(val: T) => Record<K, T> & U;
assoc<T, U, K extends string>(prop: K, val: T, obj: U): Record<K, T> & U;
assoc<T, K extends string>(prop: K, val: T): <U>(obj: U) => Record<K, T> & U;
assoc<K extends string>(prop: K): <T, U>(val: T, obj: U) => Record<K, T> & U;
我不确定,但我认为这是对 @types/ramda
项目的疏忽。您可以通过 declaration merging 以这种方式增强类型定义:
interface Static {
prop<P extends keyof T, T>(p: P): (obj: Record<P, T>) => T;
assoc<K extends keyof T, T>(prop: K): <T, U>(val: T, obj: U) => Record<K, T> & U;
}
然后像这样输入您的 updateKey
方法,无需单独的块来处理不同的键类型:
const updateKey = <K extends keyof IAsset>(key: K) => R.lens(R.prop<K, IAsset>(key), R.assoc<K, IAsset>(key));
打字稿错误
(method) R.Static.prop(p: string): (obj: Record) => T (+3 overloads)
Returns a function that when supplied an object returns the indicated property of that object, if it exists.
Argument of type '(obj: Record) => T' is not assignable to parameter of type '(s: {}) => {}'. Types of parameters 'obj' and 's' are incompatible. Type '{}' is not assignable to type 'Record'. Index signature is missing in type '{}'.ts(2345)
代码:
https://ramdajs.com/docs/#lens
// Changes value of key in object without mutation
export const updateKey = (key: string) => R.lens(R.prop(key), R.assoc(key));
如何使用此功能
interface IMyObj {
position: number;
price: number;
value: number;
}
const myObj: IMyObj = {
position: 1,
price: 100,
value: 100
}
const updateKey = (key: string) => R.lens(R.prop(key), R.assoc(key));
const newObj = R.set(updateKey('value'), 200, myObj);
console.log('newObj', newObj); // {"position":1,"price":100,"value":200}
在我的实际应用中,我的 IAsset 对象的签名如下所示:
export interface IAsset {
[key: string]: string | number | undefined | boolean;
availableSupply?: string;
currency: string;
exchange: string;
exchange_base?: string;
marketCap: number;
name: string;
percentage?: number;
price: number;
position?: number;
value?: number;
inWatchlist?: boolean;
}
// Changes value of key in object without mutation
export const updateKey = (key: IAsset[string]) => {
if (key) {
return R.lens(R.prop(key), R.assoc(key));
}
}
但是它仍然产生这个 Typescript 警告:
Argument of type '(obj: Record) => T' is not assignable to parameter of type '(s: {}) => {}'. Types of parameters 'obj' and 's' are incompatible. Type '{}' is not assignable to type 'Record'. Index signature is missing in type '{}'.ts(2345)
另请注意,Typescript 正在扼杀漂亮的小型 1 行 Ramda 函数的乐趣。
对于你原来的问题:
我不是 Ramda 方面的专家,所以也许我遗漏了一些有关如何使用这些类型的信息,但看起来您可以通过使 updateKey
通用来消除类型错误:
const updateKey = <T, K extends string>(key: K) => R.lens(R.prop<K, T>(key), R.assoc(key));
请注意,此处的类型推断不会很好。如果将鼠标悬停在 updateKey("value")
上,推断类型将为 <{}, "value">(key: "value") => Lens
,因此在某些情况下您可能需要明确指定类型参数。
对于您更新的问题:
我肯定缺少某些东西。 IAsset
的界面不支持数字键——仅支持字符串。所以 应该 除了字符串之外不需要担心任何其他事情,但是,为了论证,我们假设您还想处理数字或符号键。
如果你看@types/ramda
,prop
and assoc
的单参数重载只接受字符串:
/**
* Returns a function that when supplied an object returns the indicated property of that object, if it exists.
*/
prop<T>(__: Placeholder, obj: T): <P extends keyof T>(p: P) => T[P];
prop<P extends keyof T, T>(p: P, obj: T): T[P];
prop<P extends string>(p: P): <T>(obj: Record<P, T>) => T;
prop<P extends string, T>(p: P): (obj: Record<P, T>) => T;
/**
* Makes a shallow clone of an object, setting or overriding the specified property with the given value.
*/
assoc<T, U>(__: Placeholder, val: T, obj: U): <K extends string>(prop: K) => Record<K, T> & U;
assoc<U, K extends string>(prop: K, __: Placeholder, obj: U): <T>(val: T) => Record<K, T> & U;
assoc<T, U, K extends string>(prop: K, val: T, obj: U): Record<K, T> & U;
assoc<T, K extends string>(prop: K, val: T): <U>(obj: U) => Record<K, T> & U;
assoc<K extends string>(prop: K): <T, U>(val: T, obj: U) => Record<K, T> & U;
我不确定,但我认为这是对 @types/ramda
项目的疏忽。您可以通过 declaration merging 以这种方式增强类型定义:
interface Static {
prop<P extends keyof T, T>(p: P): (obj: Record<P, T>) => T;
assoc<K extends keyof T, T>(prop: K): <T, U>(val: T, obj: U) => Record<K, T> & U;
}
然后像这样输入您的 updateKey
方法,无需单独的块来处理不同的键类型:
const updateKey = <K extends keyof IAsset>(key: K) => R.lens(R.prop<K, IAsset>(key), R.assoc<K, IAsset>(key));