typescript “未知”类型的参数不能分配给“{}”类型的参数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/56485202/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Argument of type 'unknown' is not assignable to parameter of type '{}'
提问by jcalz
Here is my code
这是我的代码
const Res = await fetch(`https://foo0022.firebaseio.com/.json`);
const ResObj = await Res.json();
if (!Res.ok || !ResObj) {
throw new Error("Page Not Found 404");
}
const ResArr = await Object.values(ResObj)
.map(v => Object.values(v).flat())//error
.flat()
.filter(({ title }) => title.includes(Search))
In the line In the line I get this error ".map (v => Object.values (v) .flat ())" I get this error Argument of type 'unknown' is not assignable to parameter of type '{}'.How can this problem be solved?
在行 在行中,我收到此错误“.map (v => Object.values (v) .flat ())” 我收到此错误“未知”类型的参数不可分配给“{}”类型的参数.如何解决这个问题?
回答by jcalz
The problem here is that you need to help TypeScript understand the types of the objects you're dealing with. The fetch
API can't know in advance what the shape of the returned objects are going to be, so you have to define it and assert that he results conform to it.
这里的问题是你需要帮助 TypeScript 理解你正在处理的对象的类型。该fetch
API无法事先知道返回的对象的形状将是,所以你必须定义,并断言他结果符合它。
Looking at what's at https://foo0022.firebaseio.com/.json, I'd suggest something like the following:
查看https://foo0022.firebaseio.com/.json 上的内容,我建议如下:
interface ResObj {
Mens: {
Hat: Clothing[];
Hymanet: Clothing[];
Pants: Clothing[];
Shoes: Clothing[];
Suit: Clothing[];
};
New: Clothing[];
}
interface Clothing {
agility: boolean[];
alt: string;
color: string[][];
id: string;
location?: string; // fix this
Location?: string; // fix this
material: string;
price: string[][];
prodState: string;
saiz: string[][];
shipping: string;
sold: string;
src: string[][];
title: string;
to: string;
}
But of course whether or not that's accurate depends on some kind of API documentation. Assuming that's right, you can go a bit further:
但当然这是否准确取决于某种 API 文档。假设这是正确的,您可以更进一步:
const Res = await fetch(`https://foo0022.firebaseio.com/.json`);
const ResObj: ResObj | undefined = await Res.json();
if (!Res.ok || !ResObj) {
throw new Error("Page Not Found 404");
}
Now ResObj
will be known as type ResObj
and you can start manipulating it. One issue is that the standard library's typings for Object.values()
and Array.prototype.flat()
don't reflect what you're doing with them. We can build some custom typings for them... but in this case I'll just wrap them with new functions whose types match:
现在ResObj
将被称为类型ResObj
,您可以开始操作它。一个问题是标准库的类型Object.values()
并Array.prototype.flat()
没有反映你正在用它们做什么。我们可以为它们构建一些自定义类型……但在这种情况下,我将使用类型匹配的新函数包装它们:
// return an array of all object values...
// if the object is already an array, the output is the same type.
// otherwise it's the union of all the known property types
function vals<T extends object>(
arr: T
): Array<T extends Array<infer U> ? U : T[keyof T]> {
return Object.values(arr); // need es2017 lib for this
}
// Flatten an array by one level...
function flat<T>(
arr: Array<T>
): Array<Extract<T, any[]>[number] | Exclude<T, any[]>> {
return arr.flat(); // need esnext lib for this
}
Those functions typings might be confusing if you've never used TypeScript before, especially since they rely on conditional typesto tease out the array properties.
如果您以前从未使用过 TypeScript,那么这些函数类型可能会令人困惑,尤其是因为它们依赖条件类型来梳理数组属性。
Then we can rewrite your code like this:
然后我们可以像这样重写你的代码:
const ResArr = flat(vals(ResObj).map(v => flat(vals(v)))).filter(
({ title }) => title.includes(Search)
);
And there are no errors, and the compiler understands that ResArr
is an array of Clothing
objects.
并且没有错误,编译器知道这ResArr
是一个Clothing
对象数组。
Okay, hope that helps; good luck!
好的,希望有帮助;祝你好运!
回答by Shaun Luttin
Problem
问题
Res.json()
returns a value of type any
, and when Object.values
receives input of type any
, it returns an unknown[]
. When strictNullChecks
is on, TypeScript will not let us assign a value of type unknown
to a parameter of type {}
.
Res.json()
返回一个类型的值any
,当Object.values
接收到类型的输入时any
,它返回一个unknown[]
. 当strictNullChecks
打开时,TypeScript 不会让我们将 type 的值分配给 typeunknown
的参数{}
。
That explanation is also inline with the comments.
该解释也符合评论。
const func = async () => {
const Res = await fetch(`https://foo0022.firebaseio.com/.json`);
/**
* The ResObj is that `Res.json()` returns is of type `any`.
*/
const ResObj = await Res.json();
if (!Res.ok || !ResObj) {
throw new Error("Page Not Found 404");
}
/**
* When we pass Object.values a type of `any`,
* it produces an array of type `unknown[]`.
*/
const unknownArray = Object.values(ResObj);
/**
* `Object.values` has two signatures:
*
* * `values(o: {}): any[];`
* * `values<T>(o: { [s: string]: T } | ArrayLike<T>): T[];`
*
* When `strictNullCheck` is `true`, we cannot assign `unknown` to `{}`.
*/
const ResArr = unknownArray.map(unknownItem => Object.values(unknownItem));
};
Two Possible Solutions
两种可能的解决方案
- Disable
strictNullChecks
(not recommended). - Add a type to the
ResObj
.
- 禁用
strictNullChecks
(不推荐)。 - 将类型添加到
ResObj
.
The latter option looks like this:
后一个选项如下所示:
type MyKnownType = {
prop1: string;
prop2: number;
prop3: boolean;
};
const ResObj: MyKnownType = await Res.json();