为啥类型 `Record<string,unknown>` 不接受具有已定义键的对象作为值

Posted

技术标签:

【中文标题】为啥类型 `Record<string,unknown>` 不接受具有已定义键的对象作为值【英文标题】:why type `Record<string,unknown>` does not accept object with defined keys as value为什么类型 `Record<string,unknown>` 不接受具有已定义键的对象作为值 【发布时间】:2021-10-13 02:02:24 【问题描述】:

我正在尝试在类型中创建一个可以接受任何对象作为输入的函数。我把它定义为

type Props =  onSubmit: (data: Record<string, unknown>) => void;

但是当我尝试将这种类型传递给它时

type SignIn = (data: email: string, password: string) => void;

我收到此错误

Type 'SignIn' is not assignable to type '(data: Record<string, unknown>) => void'.
  Types of parameters 'data' and 'data' are incompatible.
    Type 'Record<string, unknown>' is missing the following properties from type ' email: string; password: string; ': email, password

错误的完整示例是here

搞笑this works

【问题讨论】:

【参考方案1】:

您的示例可以简化为:

declare var signin: (data:  email: string, password: string ) => void
declare var record: (data: Record<string, unknown>) => void

signin = record
record = signin // error

如果您检查参数的可分配性,这会更有趣。你会看到可分配性被颠倒了。

declare var signinArg:  email: string, password: string 
declare var recordArg: Record<string, unknown>

signinArg = recordArg // error
recordArg = signinArg

为什么signin 不能分配给recordsigninArg 可以分配给recordArg

答案是: typescript 中的函数与它们的参数是相反的。这是设计使然。

有关 TypeScript 协方差的更多信息,您可以找到 here

尝试禁用strictFunctionTypes 编译器标志。你会看到错误消失了。

以前,所有函数都是双变量的,而且不安全。

Here您可以找到非常相似的问题,但问题的上下文更多

【讨论】:

谢谢你的详细解释,如果在 TS 文档中有这个就好了 我发现只有这个参考 typescriptlang.org/docs/handbook/release-notes/…【参考方案2】:

不能将广义类型 (Record&lt;string, unknown&gt;) 分配给特定类型 ( email: string, password: string ),反之亦然。

type SignIn = (data: Record<string, unknown>) => void;
const signIn: SignIn = ( email, password ) =>  console.log(email, password) ;

type Data =  email: string, password: string 
type Props = 
    onSubmit: (data: Data) => void
;
const onSubmit: Props =  onSubmit: signIn ;

TypeScript playground

【讨论】:

【参考方案3】:

这个问题也可以用这样的泛型来解决

type SignInData = email: string, password: string;
type SignIn = (data: SignInData) => void;
const signIn: SignIn = async (email, password) =>  console.log(email, password) ;

type Props<DATA extends Record<string, unknown>> =  onSubmit: (data: DATA) => void;

const onSubmit: Props<SignInData> = onSubmit: signIn;

【讨论】:

以上是关于为啥类型 `Record<string,unknown>` 不接受具有已定义键的对象作为值的主要内容,如果未能解决你的问题,请参考以下文章

React Navigation + TypeScript 错误:类型“EventStackParams”不满足约束“Record<string, object |未定义>'

无法将空对象设置为 Record 类型的参数的默认值

当类型是 Record <k,v> - NestJS 时,类验证器不起作用

我有一个 map<string, vector<record>>,如何从 vector<record> 中删除记录?

在 Record<string, string> 中创建新属性表示可以未定义新值

c++程序 我为啥不能将string类的变量赋给char数组,我按书上打的?