foreword
There is such an object, which has two attributes: name
and title
, only one of these two attributes can appear when assigning a value, for example: when name appears, title cannot appear , when title appears, name cannot appear.
At this point, how would you define this type in TypeScript? This article will take you to implement a mutual exclusion type to solve this problem. Interested developers are welcome to read this article.
Pre-knowledge
Before implementing, we need to understand a few basic knowledge.
Definition of multiple attributes of the same type in an object
There is an object that contains five optional attributes a
, b
, c
, d
, e
, They are all of type string
, and the way most people define them should look like this:
type obj = {
a?:string;
b?:string;
c?:string;
d?:string;
e?:string;
}
So, is there a better way 😼, the answer is yes, please watch my performance:
type obj = { [P in "a" | "b" | "c" | "d" | "e"]?: string };
never type
In TypeScript it has a special type never
which is a subtype of all types and cannot be subdivided any more, which means that there is no type to assign to it other than itself.
Let's take an example to explain the above statement, as follows:
- We define a variable
amazing
and assign it the type never. - We assign different types of values to it, all of which fail to compile because it can no longer be subdivided.
let amazing: never;
amazing = 12;// 报错:amazing是never类型不能分配给number类型
amazing = true;// 报错:amazing是never类型不能分配给boolean类型
amazing = "真神奇";// 报错:amazing是never类型不能分配给string类型
amazing = {};// 报错:amazing是never类型不能分配给{}类型
amazing = [];// 报错:amazing是never类型不能分配给[]类型
Remove properties from union types
There is a set of union types "a" | "b" | "c" | "d"
, we want to strip out attributes b and c, in TS there is a function called Exclude
which can be used to do this, accepting two parameter:
- UnionType union type
- ExcludedMembers properties that need to be excluded
The usage method is as follows:
type P = Exclude<"a" | "b" | "c" | "d", "b" | "c"> // "a" | "d"
Convert all properties in object to union type
There is an object which contains 2 optional properties name
, title
, we want to convert it to union type name | title
keyof
function, he can be used to deal with this problem, the use method is as follows:
type A = { [P in "name" | "title"]?: string };
type UnionType = keyof A; // "name" | "title"
Implementing Mutex Types
With the pre-knowledge as a foreshadowing, then we can use it to define a mutually exclusive type to solve the problem described at the beginning of the article.
Next, let's sort out the implementation ideas:
- Implement an exclusion type to remove the attributes in the B object type from the A object type, and set the excluded attribute type to never to get a new object type.
- The mutual exclusion type is implemented based on the exclusion type, the object types A and B are substituted into the exclusion type, and they are excluded from each other, and the two results are connected by the OR operator.
Smart developers may have guessed the principle, yes, some properties are set to never. 🤓
implementation code
Next, let's look at the implementation of the code, as follows:
// 定义排除类型:将U从T中剔除, keyof 会取出T与U的所有键, 限定P的取值范围为T中的所有键, 并将其类型设为never
type Without<T, U> = { [P in Exclude<keyof T, keyof U>]?: never };
// 定义互斥类型,T或U只有一个能出现(互相剔除时,被剔除方必须存在)
type XOR<T, U> = (Without<T, U> & U) | (Without<U, T> & T);
Note: For the reusability of types, we use generics, developers who are not familiar with this, please go to: TypeScript Chinese website - generics
test case
Let's put the problem mentioned at the beginning of the article into the above implementation code and see if it can solve it 😌, as follows:
// A类型
type A = {
name: string;
};
// B类型
type B = {
title: string;
};
// A和B两种类型只有一个能出现
type AOrB = XOR<A, B>;
// 传值测试
const AOrB1: AOrB = { name: "姓名" }; // 编译通过
const AOrB2: AOrB = { title: "标题" }; // 编译通过
const AOrB3: AOrB = { title: "标题", name: "姓名" }; // 报错: Type '{ title: string; name: string; }' is not assignable to type 'AOrB'.
const AOrB4: AOrB = { name: "姓名", otherKey: "" }; // 报错:Type '{ name: string; otherKey: string; }' is not assignable to type 'AOrB'.
When two properties appear at the same time, the editor throws a type error directly (we set the type of all excluded properties to never, so when you assign any value to it, it will report a type error), as shown in the following figure Show:
Use case teardown
Some developers may be confused about the above test cases, and they know them all when they are disassembled, because they are all covered in the prerequisite knowledge, but they don't know when they are written together😹, it doesn't matter, then I will disassemble them all. , the code looks like this:
type AOB = ({ name?: never } & {
title: string;
}) | ({ title?: never } & {
name: string;
});
// 传值测试
const a: AOB = { name: "姓名" }; // 编译通过
const b: AOB = { title: "标题" }; // 编译通过
const c: AOB = { title: "标题", name: "姓名" }; // 报错
const d: AOB = { title: "标题", otherKey: "" }; // 报错
Seeing this, there may be some developers who don't understand it, so start to tap in the editor. If you don't understand it, save this article first, and when you have time in the future, take it out and learn it. One study.
write at the end
At this point, the article is shared.
I'm an amazing programmer , a front-end developer.
If you are interested in me, please visit my personal website to learn more.
- If there are any mistakes in the article, please correct them in the comment area. If this article helps you, please like and follow 😊
- This article was first published on the magical programmer's official account, and reprinting is prohibited without permission 💌
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。