typescript - 这种 DeepPartial 类型如何在 Typescript 中工作?
问题描述
我在这里查看了这个问题:
最佳答案的 DeepPartial 类型定义如下:
type DeepPartial<T> = {
[P in keyof T]?: DeepPartial<T[P]>;
};
我进行了测试,这种类型按预期工作,但我无法完全理解它是如何在内部工作的。
让我们从同一个问题中获取示例界面:
interface Foobar {
foo: number;
bar: {
baz: boolean;
qux: string;
};
}
当 P=bar 时,很容易理解它会递归地进入
DeepPartial<{
baz: boolean;
qux: string;
}>
并使“baz”和“qux”键可选。
但我没有得到的是原始类型的递归是如何工作的?像foo
key 一样,怎么DeepPartial<number>
一样number
?当 T=数字时,
[P in keyof number]?: DeepPartial<number[P]>;
对我来说没有意义。
在我看来,DeepPartial 的实现应该是这样的:
type DeepPartial<T> = {
[P in keyof T]?: isPrimitive(T[P]) ? T[P] : DeepPartial<T[P]>;
};
但原始实现也有效,我不明白如何。
我希望我能很好地解释我的问题。这是示例游乐场:
编辑: 我进一步调查发现
type DeepPartial<T> = {
[P in keyof T]?: any;
};
type DeepPartialTest<T> = {
[P in keyof number]?: any;
};
现在DeepPartial<number>
将返回数字类型,但DeepPartialTest<number>
不会。这对我来说更奇怪。
编辑2添加截图:
这按预期工作:
这不会:
实际上,两者应该是相同的吗?
解决方案
我认为问题是“为什么作用于原语的映射类型会产生相同的原语,为什么它似乎只是有时发生”而不是DeepPartial
本身,对吧?
映射类型有两种“风格”。有正常映射类型只迭代属性键文字的任意联合(例如,{[P in K]: ...}
),以及专门迭代另一种类型的键(例如,)的同态{[P in keyof T]: ...}
映射类型,并尝试通过以下方式保留该类型的结构,比如说,将修饰符readonly
和?
从输入类型复制到输出类型(除非您使用自己的readonly
or?
和+
or更改修饰符-
)。例子:
interface Obj {
a?: number,
b: string,
readonly c: boolean
}
type Homomorphic<T> = {
[K in keyof T]: Array<T[K]>
}
type ObjHom = Homomorphic<Obj>
/* type ObjHom = {
a?: (number | undefined)[] | undefined;
b: string[];
readonly c: boolean[];
} */
type ObjKeys = keyof Obj;
type ObjNonHom = {
[K in ObjKeys]: Array<Obj[K]>
}
/* type ObjNonHom = {
a: (number | undefined)[];
b: string[];
c: boolean[];
} */
在上面的代码中,ObjHom
和ObjNonHom
是类似的,但是ObjHom
' 的a
属性是可选的,它的c
属性是readonly
(就像 in 一样Obj
);whileObjNonHom
的属性都是必需且可变的。
能够确定特定映射类型何时是同态的可能很棘手,因为涉及到很多启发式方法。一般来说,根据未解析的泛型参数而具有某种类型in keyof T
的映射类型将是同态的。T
一般来说,一个映射类型以in X
whereX
是某种类型而没有keyof
直接在其中的类型将是非同态的。当映射类型特征in keyof T
是T
一些非泛型类型时,事情就变得不确定了。对于像number
这样的原语往往是非同态的,但对于对象类型它往往是同态的。我可能可以通过 GitHub 找到实现每个启发式的 PR,但我不知道是否值得任何人为此花时间。
在microsoft/TypeScript#12447中介绍了原语的特定行为。在描述中,它说:
形式的映射类型(
{ [P in keyof T]: X }
其中T
是某个类型参数)被称为 [同态] 映射类型,因为它生成的类型与 具有相同的形状T
。[...] [当] 在同构映射类型中替换原始类型时T
,我们只需生成该原始类型。例如,当{ [P in keyof T]: X }
用A | undefined
for T 实例化时,我们产生{ [P in keyof A]: X } | undefined
.
所以这个问题的基本答案是:当映射类型是同态的并且作用于原始类型时,就会出现相同的原始类型。原是DeepPartial
同态的,所以number
变成number
。您的修改版本in keyof number
直接是非同态的,因此number
成为一种类型,每个明显的属性都number
映射到可选属性。
推荐阅读
- react-native - console.error react native version mismatch javascript validation 0.59.9 和 native version 0.60.0 确保你有
- asp.net-mvc - SQL Server 2016 未连接到本地数据库
- ruby-on-rails - 使用什么更好的redis锁定机制来避免rails中的异步验证失败?
- python - 为什么简单的 Python 程序会随着时间的推移而变慢?
- c# - 如何在c#中运行异步代码并返回值?
- c - 为什么scanf将每个字母都读取为39?
- c - 如何找到使随机数序列保持在 C 中的下一个种子?
- css - 有没有办法固定 html 中所有屏幕尺寸和分辨率的环内径尺寸
- rest - REST 文件下载需要 5 分钟才能完成
- c# - 为 Xamarin.Forms 中的按钮选择处理程序或命令的最佳实践