在一个TypeScrip项目中,有这样一个类型定义:

type Foo = {
  a: string;
  b: string;
  metadata: {
    c: string;
    d: string;
  };
};

它是从其他地方进口的,在其他地方也用得很多,所以我不能改变它.

我想创建一个以Foo为参数的函数,但ametadata.c是可选的,因为我可以在此上下文中为这些字段设置有意义的默认值:

function doSomething(foo: {
  a?: string;
  b: string;
  metadata: {
    c?: string;
    d: string;
  };
}): void {
  // do whatever
}

实际的类型要大得多,而且会不时更新,所以完全复制它的定义来添加两个问号不是一个 Select .

以下是我try 过的:

Foo & { a?: string; metadata: { c?: string } }

不起作用,因为这会同时创建一个Foo{ a?: string; metadata: { c?: string } }的类型.这基本上只是Foo,因为Foo的所需属性"赢"了.如果我有逆问题(这里需要的Foo中的可选属性),我可能会起作用.

Exclude<Foo, { a?: string; metadata: { c?: string } }>

不起作用,因为Foo不是类型联合,而Exclude只能从类型联合中排除类型.它不能从类型文字定义的类型中"减go "单个属性.

Partial<Foo>

使Foo的所有属性均为可选.我不想这样.

Omit<Foo, 'a'> & { a?: string }

Omit成功地将aFoo中删除.然后,我可以将a作为可选属性添加回来.然而,我不知道如何处理c,因为它嵌套在metadata中.

做这件事最好的办法是什么?

推荐答案

可以从doSomething参数的Foo派生类型,而无需修改Foo.因为TypeScrip的类型系统是 struct 化的(基于类型的形状),而不是名义的(基于形状的名称/标识),所以您可以保持Foo赋值与您的新类型兼容,这意味着您可以将Foo个类型的参数传递给doSomething,但您可以将also个参数传递给您的新类型.

这里有一种定义新类型的方法-注意,我们从Foo中获取所有类型信息,而不是我们需要调整ametadata.c的信息:

type SpecialFoo = Omit<Foo, "a" | "metadata"> & {
    a?: Foo["a"];
    metadata: Omit<Foo["metadata"], "c"> & {
        c?: Foo["metadata"]["c"];
    };
};

然后doSomething接受其中之一:

function doSomething(foo: SpecialFoo): void {
    // do whatever
    console.log(foo);
}

在这一点上,这些工作:

// Works
doSomething({ b: "b", metadata: { d: "d" } });
// Works
doSomething({ a: "a", b: "b", metadata: { c: "c", d: "d" } });

但是,正如人们所希望的那样,这些具有无效值ac的示例不起作用:

// Error as desired, `a` has the wrong type
doSomething({ a: 42, b: "b", metadata: { d: "d" } });
// Error as desired, `c` has the wrong type
doSomething({ b: "b", metadata: { c: 42, d: "d" } });

Playground link

Typescript相关问答推荐

如何使用axios在前端显示错误体

带有联合参数的静态大小数组

如何在排版中正确键入中间件链和控制器链

无法正确推断嵌套泛型?

对扩展某种类型的属性子集进行操作的函数

React重定向参数

如何将CSV/TXT文件导入到服务中?

使用Redux Saga操作通道对操作进行排序不起作用

使用KeyOf和Never的循环引用

如何使用模板继承从子组件填充基础组件的画布

声明文件中的类型继承

常量类型参数回退类型

为什么我在这个重载函数中需要`as any`?

使用泛型识别对象值类型

我不明白使用打字脚本在模板中展开参考

使用来自API调用的JSON数据的Angular

打字脚本错误:`不扩展[Type]`,而不是直接使用`[Type]`

必须从注入上下文调用Angular ResolveFn-inject()

两个子组件共享控制权

使用 TypeScript 在 SolidJS 中绘制 D3 力图