类型 'string' 不可分配给类型 keyof in Immutable.js

Type 'string' is not assignable to type keyof in Immutable.js

我在尝试使用 fromJS 函数中的不可变 js reviver 时遇到此输入错误。

检查这个 TS playground,我可以在那里复制它。

interface User {
  name: string;
  age: number;
}

// Taken from typing definition of Immutable.js with some modification to simplify it
// https://github.com/immutable-js/immutable-js/blob/main/type-definitions/immutable.d.ts#L4955
function fromJS(
    jsValue: unknown,
    reviver?: (
      key: string | number,
      value: ''      
    ) => unknown
  ): unknown {
    return '';
  };

// My custom function for reviver, 
// I used `Extract` to ensure that it gets the string only
export function modelReviver<T>(mapper: Partial<T>): (key: Extract<keyof T, string>, value: any) => any {  
  return (key, value) => (mapper.hasOwnProperty(key) ? mapper[key] : fromJS(value));
}

const model = modelReviver<User>({
  name: 'thomas'
});

fromJS({}, model) // typing error

说的错误

Types of parameters 'key' and 'key' are incompatible.
  Type 'string | number' is not assignable to type 'keyof User'.
  Type 'string' is not assignable to type 'keyof User'

我知道问题与 key 参数有关,并且由于 key 来自 Immutable.js,所以我无法修改它。想知道为什么我在modelReviver上指定的Extract无法解决问题。

有人知道为什么会这样吗?谢谢

不确定这是否会破坏您的任何功能,因为我几乎不知道您正在尝试做什么。但是你可以通过说你想要 fromJS 中的用户密钥来摆脱错误,就像这样:

function fromJS(
    jsValue: unknown,
    reviver?: (
      key: keyof User,
      value: ''      
    ) => unknown
  ): unknown {
    return '';
  };

您可以对此进行扩展,在其中使用 keyof T 使 fromJS 通用。

您遇到的问题是字符串无法分配给 keyof User,因为 keyof User 比字符串更具体。

无法将泛型传递给 fromJS,唯一的方法是按预期输入密钥 string | number

下面是一个示例:

interface User {
  name: string;
  age: number;
}

function fromJS(
    jsValue: unknown,
    reviver?: (
      key: string | number,
      value: ''      
    ) => unknown
  ): unknown {
    return '';
  };

export function modelReviver<T>(mapper: Partial<T>): (key: string | number, value: any) => any {  
  return (key, value) => (mapper.hasOwnProperty(key) ? mapper[key as keyof T] : fromJS(value));
}

const model = modelReviver<User>({
  name: 'thomas'
});

fromJS({}, model)