我有这个界面:
export interface UserSettings
{
one: {
three: number;
four: number;
};
two: {
five: number;
six: number;
};
}
...并想把它变成这个:
export interface UserSettingsForUpdate
{
one?: {
three?: number;
four?: number;
};
two?: {
five?: number;
six?: number;
};
}
...但是Partial<UserSettings>
产生了这个:
{
one?: {
three: number;
four: number;
};
two?: {
five: number;
six: number;
};
}
是否可以使用映射类型使所有深度上的所有属性都可选,或者我是否必须手动创建接口?
答案 0 :(得分:18)
随着2.8中的条件类型的登陆,我们现在可以如下声明一个递归部分类型。
type RecursivePartial<T> = {
[P in keyof T]?:
T[P] extends (infer U)[] ? RecursivePartial<U>[] :
T[P] extends object ? RecursivePartial<T[P]> :
T[P];
};
参考:
http://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html
答案 1 :(得分:15)
您可以创建自己的映射类型,如下所示:
type RecursivePartial<T> = {
[P in keyof T]?: RecursivePartial<T[P]>;
};
不幸的是,这对于数组类型的字段不起作用。 似乎还没有办法进行条件类型映射;即限制原语。请参阅https://github.com/Microsoft/TypeScript/pull/12114#issuecomment-259776847现在可能,请参阅其他答案。
答案 2 :(得分:1)
所提供的解决方案都不够好。这是一个解释:
const x: RecursivePartial<{dateValue: Date}> = {dateValue: 0}; // ja-ja-ja
在上面的代码中,dateValue
的实际类型是RecursivePartial<Date> | undefined
,它可以分配任何值!!!
dateValue
的预期类型仅为Date
,但是规则T[P] extends object ? RecursivePartial<T[P]>
太宽。
解决方案是分离基元并消除extends object
:
export type RecursivePartial<T> = {
[P in keyof T]?:
T[P] extends Array<infer U> ? Array<Value<U>> : Value<T[P]>;
};
type AllowedPrimitives = boolean | string | number | Date /* add any types than should be considered as a value, say, DateTimeOffset */;
type Value<T> = T extends AllowedPrimitives ? T : RecursivePartial<T>;
答案 3 :(得分:0)
我已经建立了一个图书馆tsdef,该图书馆具有许多类似的常见模式/摘要。
在这种情况下,您可以像下面这样使用它:
import { DeepPartial } from 'tsdef';
let o: DeepPartial<{a: number}> = {};