如何创建一个条件泛型类型,该类型在未定义时有值,但在未定义时没有值以及其他情况

dis*_*nte 6 typescript typescript-generics

我有一种类型,我想将对象键定义为可选,any如果我不给出任何值

type OptionalData<T> = T extends undefined ? { data?: any } : { data: T };

export type DataObject<T = any> = {
  item?: string | null;
} & OptionalData<T>;

Run Code Online (Sandbox Code Playgroud)

它工作正常,直到我将我的通用设置为something | undefined

const data: DataObject<string | undefined> = { data: true }; // WRONG!
const data2: DataObject<string | number> = { data: true }; // CORRECT
Run Code Online (Sandbox Code Playgroud)

因为我的通用也可以扩展undefined我获取数据作为可选any

ipt

有没有办法说“any当它可以扩展时它只是可选的undefined”或者这样?

操场

Win*_*ing 7

问题

\n

你有这些类型:

\n
type OptionalData<T> = T extends undefined ? { data?: any } : { data: T };\n\nexport type DataObject<T = any> = {\n  item?: string | null;\n} & OptionalData<T>;\n
Run Code Online (Sandbox Code Playgroud)\n

当您键入一个变量时,DataObject类型参数是类型的联合(例如string),并且undefined您希望将数据属性键入为联合类型,但它的类型为any

\n
const data: DataObject<string | undefined> = { data: ... }\n\n// data.data should be typed as `string | undefined` however\n// data.data is typed as `any`\n
Run Code Online (Sandbox Code Playgroud)\n

怎么了?

\n

TypeScript 的条件类型文档在这里很有用。上面写着:

\n
\n

检查类型是裸类型参数的条件类型称为分布式条件类型。分布式条件类型在实例化期间自动分布在联合类型上。例如,T extends U ? X : Y带有类型参数的实例化A | B | C for T被解析为(A extends U ? X : Y) | (B extends U ? X : Y) | (C extends U ? X : Y)

\n
\n

\xe2\x80\x93有关分配条件类型的文档

\n

所以在你的情况下它解决了

\n
| (string extends undefined ? { data?: any } : { data: T })\n| (undefined extends undefined ? { data?: any } : { data: T })\n
Run Code Online (Sandbox Code Playgroud)\n

第一个条件解析为{ data: T },第二个条件解析为{ data?: any }。我相信联合类型将解析为最通用的类​​型,因此该类型最终是{ data?: any }.

\n

解决方案

\n

这里已OptionalData更新,以便它按预期工作:

\n
type OptionalData<T> = [T] extends [undefined] ? { data?: any } : { data: T };\n
Run Code Online (Sandbox Code Playgroud)\n

我们只是用方括号( )将T和包裹起来,将它们转换为元组(或者技术上来说是单元组,因为它只有一个元素)。这是演示undefined[]

\n

为什么这有效?

\n

让我们再次回顾一下条件类型的文档,并重点强调重要部分:

\n
\n

检查类型是裸类型参数的条件类型称为分布式条件类型。分布式条件类型自动分布在联合类型上

\n
\n

当我们将这些裸类型转换为元组时,它们就不再是裸的了。因为他们不再赤身露体,所以他们不再被分发。

\n