TypeScript 2.1中的递归部分<T>

Chr*_*und 32 typescript

我有这个界面:

export interface UserSettings
{
    one: {
        three: number;
        four: number;
    };
    two: {
        five: number;
        six: number;
    };
}
Run Code Online (Sandbox Code Playgroud)

...并想把它变成这个:

export interface UserSettingsForUpdate
{
    one?: {
        three?: number;
        four?: number;
    };
    two?: {
        five?: number;
        six?: number;
    };
}
Run Code Online (Sandbox Code Playgroud)

......但Partial<UserSettings>产生了这个:

{
    one?: {
        three: number;
        four: number;
    };
    two?: {
        five: number;
        six: number;
    };
}
Run Code Online (Sandbox Code Playgroud)

是否可以使用映射类型使所有深度上的所有属性都可选,或者我是否必须手动创建接口?

Jef*_*son 34

随着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];
};
Run Code Online (Sandbox Code Playgroud)

参考:

http://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html

  • 如果任何属性已经是可选的,则这将不起作用。将“T[P] extends object”替换为“T[P] extends (object | undefined)”来修复。 (7认同)
  • 这很棒.如果这个声明随lib.d.ts中的typescript一起提供,那将是非常好的. (6认同)

Mei*_*hes 17

你可以制作自己的映射类型,如下所示:

type RecursivePartial<T> = {
    [P in keyof T]?: RecursivePartial<T[P]>;
};
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

不幸的是,这对于数组类型的字段不起作用.似乎还没有办法进行条件类型映射; 即限制原语.请参阅https://github.com/Microsoft/TypeScript/pull/12114#issuecomment-259776847现在可以,请参阅其他答案.


Joo*_*oon 10

我制作了一个库tsdef,它有许多这样的常见模式/片段。

对于这种情况,您可以像下面这样使用它:

import { DeepPartial } from 'tsdef';

let o: DeepPartial<{a: number}> = {};
Run Code Online (Sandbox Code Playgroud)

  • 非常好的库,有很多例子可供学习。来源在这里https://github.com/joonhocho/tsdef/blob/master/src/index.ts (2认同)

小智 9

所提供的解决方案都不够好。这是一个解释:

const x: RecursivePartial<{dateValue: Date}> = {dateValue: 0}; // ja-ja-ja
Run Code Online (Sandbox Code Playgroud)

在上面的代码中, 的实际类型dateValue允许RecursivePartial<Date> | undefined分配任何值!的预期类型dateValue是 just 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>;
Run Code Online (Sandbox Code Playgroud)