为什么TypeScript`never`类型需要问号?对于条件对象
这段代码可以很好地有条件地要求该isDirty字段成为讲座对象的一部分:
- 如果
id是 typestring,我必须添加一个isDirty字段: - 如果
id是 typenumber,则无法isDirty向对象添加字段。
type LectureT = LectureIdT & {
title: string;
};
/**
* Lecture must have an `isDirty` field if `id` is of type string, but should have no `isDirty` field if `id` if of type number.
*/
type LectureIdT =
| { id: string; isDirty: boolean }
| { id: number; isDirty?: never };
const lectureMockWithNumberId: LectureT = {
id: 1,
title: 'Lecture 1',
// isDirty: false, // Uncomment to see error
};
const lectureMockWithStringId: LectureT = {
id: "1",
title: 'Lecture 2',
isDirty: false,
};
可以在此TS Playground 中使用此代码。
问题:为什么我需要问号isDirty?: never?
我对此事的调查:
当我删除问号isDirty?: never以获取isDirty: never它不再起作用时:
type LectureIdT =
| { id: string; isDirty: boolean }
| { id: number; isDirty: never };
lectureMockWithNumberId 突然有一个打字稿错误:
Type '{ id: number; title: string; }' is not assignable to type 'LectureT'.
Type '{ id: number; title: string; }' is not assignable to type '{ id: number; isDirty: never; } & { title: string; }'.
Property 'isDirty' is missing in type '{ id: number; title: string; }' but required in type '{ id: number; isDirty: never; }'.
我们在最后一句话中看到它说这isDirty是必需的。但这对我来说似乎不对!它的类型是never-> 所以它永远不是必需的,不是吗?
为什么我必须添加一个问号才能使其工作。这似乎不合逻辑。
为了理解它,我将其更改为isDirty: never | undefined:
type LectureIdT =
| { id: string; isDirty: boolean }
| { id: number; isDirty: never | undefined };
但令我惊讶的是,错误仍然存在!不是?in ega?: string等于a: string | undefined吗?
我不明白...
- ......为什么问号
?在这里首先是必要的,而且isDirty: never;基本上是不可能的。 - ...为什么
?当它与 一起使用时表现不同never?
回答
让我一一回答这些问题:
我们在最后一句话中看到它说这
isDirty是必需的。但这对我来说似乎不对!它的类型是never-> 所以它永远不是必需的,不是吗?
never就其与可选对象属性的交互方式而言,该类型没有任何独特之处。你可以认为never是相同的任何其他类型的(string,number,等等)。不同之处在于,与这些其他类型不同,没有可分配给 的值never。你可能会说一个类型的变量never“永远”不能被赋予一个有效的值。
但令我惊讶的是,错误仍然存在!不是
?in ega?: string等于a: string | undefined吗?
不。考虑两个对象之间的区别:{}和{a: undefined}。在一种情况下,钥匙完全丢失了。在另一个中它存在并具有值undefined。前一个对象可分配给{a?: string}但不能分配给{a: string | undefined}。
这将导致:
为什么问号
?在这里首先是必要的,而且isDirty: never;基本上是不可能的。
像上面的例子一样,如果你没有?在键名上包含,那么类型中需要键。关键只是有存在。但是该键的值的类型是never. 因此,您无法为该键分配有效值。
所以简而言之,没有问号确实是不可能的,因为它是一个矛盾的要求:那个键必须存在,但没有值对其有效。
最后:
为什么
?当它与never.
这仅仅是 的通常属性never与 的通常行为相结合的结果?。这两个特定功能的交互没有什么特别之处。
使用 的示例{isDirty?: never},这意味着以下条件之一必须为真:
- 该对象并没有包含的
isDirty关键。 - 该对象确实包含
isDirty键并且它的值是 typenever。
由于这两种情况中的第二种是不可能的(根据上述参数),所以只剩下第一种情况:匹配此类型的对象不得包含isDirty键。