特定键上的部分<>

Gré*_*EUT 2 interface typescript typescript-typings

我有一个描述 mongodb 数据库数据的打字稿接口,如:

interface Foo {
  _id: string,
  name: string,

  fish: {
    _id: string,
    name: string,   
  },
}
Run Code Online (Sandbox Code Playgroud)

我有一种方法可以构建要插入数据库的数据,例如:

function pushNewFish() {
   const obj: Foo = {
      name: 'obiwan',

      fish: {
         name: 'kenobi',
      },
  };

  // ...
}
Run Code Online (Sandbox Code Playgroud)

问题是:我没有实现_id特定于数据库的每个元素。

我有可能使用,Partial<Foo>但这不是我要找的。

我也有可能把 every_id: string变成_id ?: string,但感觉不对。

有没有办法做到:

interface FooDatabase { ... }

type Foo = Partial<'_id', FooDatabase>;
Run Code Online (Sandbox Code Playgroud)

? 谢谢

iY1*_*1NQ 10

如果只有某些_id字段应该是可选的,则定义一个新的实用程序类型,该类型仅将选定的键声明为可选:

type Optional<T, K extends keyof T> = Partial<Pick<T, K>> & Omit<T, K>

interface FooDatabase {
  _id: number;
  foo: string;
  bar: string;
}

type Foo = Optional<FooDatabase, '_id'>

Run Code Online (Sandbox Code Playgroud)

游乐场链接


递归解决方案(对于嵌套对象),其中相同单例类型的每个键都是可选的:

type Primitive = number | string | boolean | undefined | null | any[];
type Optional<T, K extends keyof T> = { [P in K]?: T[P] } & { [P in Exclude<keyof T, K>]: T[P] extends Primitive ? T[P] : Optional<T[P], keyof T[P] & K> };
Run Code Online (Sandbox Code Playgroud)

游乐场链接


jca*_*alz 5

也许你想要这样的类型:

type PartialK<T, K extends PropertyKey = PropertyKey> =
  Partial<Pick<T, Extract<keyof T, K>>> & Omit<T, K> extends infer O ?
  { [P in keyof O]: O[P] } : never;
Run Code Online (Sandbox Code Playgroud)

在这里,PartialK<T, K>就像Partial<T>但只对 中的键起作用K,其余部分不理会。所以PartialK<T, keyof T>PartialK<T, PropertyKey>应该像Partial<T>. 只要T是没有索引签名、调用签名或构造签名的对象类型,这应该可以正常工作。我对条件类型做了一个小技巧,这样生成的对象类型就没有交集,就像这样:

type TestPartialK = PartialK<{ a: string, b: number, c: boolean }, "b" | "c">
/* type TestPartialK = {
    b?: number | undefined;
    c?: boolean | undefined;
    a: string;
} */
Run Code Online (Sandbox Code Playgroud)

现在它只能在一层深层次上工作,看起来您的问题想要通过嵌套对象递归地执行此操作。所以这里是NestedPartialK<T, K>

type NestedPartialK<T, K extends PropertyKey = PropertyKey> =
  T extends Function ? T :
  T extends Array<any> ? Array<NestedPartialK<T[number], K>> :
  T extends object ? PartialK<{ [P in keyof T]: NestedPartialK<T[P], K> }, K> :
  T;
Run Code Online (Sandbox Code Playgroud)

PartialK在定义中使用;它不考虑函数和原语,并使用递归类型将数组映射到数组,将对象映射到对象。请注意,它不会迭代元组,但是部分元组无论如何都很奇怪,而且您的用例甚至没有提到数组,所以我并不担心那么多。让我们看看它是否适用于您的FooDatabase

type Foo = NestedPartialK<FooDatabase, "_id">
/* type Foo = {
    _id?: string | undefined;
    foo: string;
    bar: string;
    tree: {
        _id?: string | undefined;
        again: {
            _id?: string | undefined;
            value: string;
        };
    };
} */
Run Code Online (Sandbox Code Playgroud)

在我看来很好。_id现在所有的道具都是可选的,其他的道具都保留了下来。好的,希望有帮助;祝你好运!

Playground 链接到代码