我正在使用库中自动生成的类型.这些类型包含所需的所有值,而我想将其中一些标记为可选.我知道在typescript中使用泛型是可能的,但不确定如何做到这一点.下面是我希望发生的一个例子:

这是一个嵌套类型的示例:

interface Person {
    name: string;
    hometown: string;
    nickname: string;
    data:{
        address:string,
        phone:number
    }
}

我希望调用以下内容,使根类型中的name属性和嵌套类型中的address属性成为可选的:

type TransformedPerson = MakeOptional<Person,{name:string, data:{address:string}}>

或:

type TransformedPerson = MakeOptional<Person,"name"|"data.address">

希望看到创建以下类型:

/*
type TransformedPerson = {
    name?: string;
    hometown: string;
    nickname: string;
    data:{
        address?:string,
        phone:number
    }
}
*/

我已经看到了use Partial in nested property with typescript的一个示例,它使根对象中的属性成为可选的,但它不适用于嵌套类型:

type RecursivePartial<T> = {
    [P in keyof T]?: RecursivePartial<T[P]>;
};

type PartialExcept<T, K extends keyof T> = RecursivePartial<T> & Pick<T, K>;

type TransformedType = PartialExcept<Person, "name"> /// This works only for root type

type TransformedType = PartialExcept<Person, "name"|"data.address"> /// throws error

推荐答案

以下是一种基于元组的方法,用于定义可选键:

interface Person {
    name: string;
    hometown: string;
    nickname: string;
    data: {
        address: string;
        phone: number;
    }
}

type NestedKeys<T extends string, U extends string[]> = {
  [K in keyof U]: U[K] extends `${T}.${infer V}` ? V : never;
}

type PartialExcept<T, U extends string[]> = {
  [K in keyof T as K extends U[number] ? K : never]?: T[K]
} & {
  [K in keyof T as K extends U[number] ? never : K]: K extends string
    ? PartialExcept<T[K], NestedKeys<K, U>>
    : T[K]
}

type TransformedPerson = PartialExcept<Person, ['name', 'data.address']>

const p: TransformedPerson = {
  hometown: 'Sometown',
  nickname: 'Somename',
  data: {
    phone: 132456789
  }
};

PartialExcept类型基于两个mapped types中的intersection定义了一个新类型:一个包含可选属性,其中键存在于字符串元组中,另一个包含其余必需属性.

PartialExcept类型递归使用自身.对于嵌套对象,NestedKeys类型用于创建仅包含给定属性的后代键的映射元组类型.


Playground link

Typescript相关问答推荐

如何在不使用变量的情况下静态判断运算式的类型?

类型是工作.但它失go 了正确变体的亮点..为什么?或者如何增强?

为什么缩小封闭内部不适用于属性对象,但适用于声明的变量?

JS Redux Devtools扩展不工作

将props传递给子组件并有条件地呈现它''

异步动态生成Playwright测试,显示未找到测试

为什么TypeScript假设文档对象始终可用?

编剧错误:正在等待Expect(Locator).toBeVisible()

CDK从可选的Lambda角色属性承担角色/复合主体中没有非空断言

在HighChats列时间序列图中,十字准线未按预期工作

抽象类对派生类强制不同的构造函数签名

类型脚本中参数为`T`和`t|unfined`的重载函数

如何创建一个将嵌套类属性的点表示法生成为字符串文字的类型?

任何导航器都未处理有效负载为";params";:{";roomId";:";...";}}的导航操作

TS不能自己推断函数返回类型

类型分布在第一个泛型上,但不分布在第二个泛型上

什么';是并类型A|B的点,其中B是A的子类?

确保财产存在

我应该使用服务方法(依赖于可观察的)在组件中进行计算吗?

为什么 Typescript 无法正确推断数组元素的类型?