Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

645 - Diff #3014

Open
MuYunyun opened this issue Sep 2, 2021 · 13 comments
Open

645 - Diff #3014

MuYunyun opened this issue Sep 2, 2021 · 13 comments
Labels
645 answer Share answers/solutions to a question en in English

Comments

@MuYunyun
Copy link

MuYunyun commented Sep 2, 2021

type Diff<O, O1> = Omit<O & O1, keyof (O | O1)>

解释: 在对象中使用交、并集

在对象中使用 |&,与在非对象中使用存在语义上的差异。

在集合对象中使用联合类型 | ,官网 working-with-union-types 有如下说明:

Notice that given two sets with corresponding facts about each set, only the intersection of those facts applies to the union of the sets themselves.

type Foo = {
  name: string
  age: string
}
type Bar = {
  name: string
  age: string
  gender: number
}

type result = keyof (Foo | Bar) // "name" | "age"

在集合对象中使用交集类型 & ,可以见 intersection-types 给出的 demo:

interface Colorful {
  color: string;
}
interface Circle {
  radius: number;
}

type ColorfulCircle = keyof (Colorful & Circle) // "color" | "radius"

结合 &| 的使用,我们能立马写出比如类型 diff

@MuYunyun MuYunyun added answer Share answers/solutions to a question en in English labels Sep 2, 2021
@github-actions github-actions bot added the 645 label Sep 2, 2021
@yiheinchai
Copy link

很欣赏你的解释!😁

@mefengl
Copy link
Contributor

mefengl commented Nov 6, 2022

do it without Omit

// O&O1 - O|O1
// & means 'either has', | means 'both have'
type Diff<O, O1> = {
  [K in keyof (O & O1) as K extends keyof (O | O1) ? never : K]: (O & O1)[K];
};

@L1atte
Copy link

L1atte commented Dec 30, 2022

这部分我有些疑惑,似乎在使用联合类型 Foo | Bar 的时候,既可以是两者的交集也可以是两者的并集
这是 playground 的测试例子

type Foo = {
  name: string
  age: string
  gender: number
}
type Bar = {
  name: string
  age: string
}
// 并集情况,OK
let m: (Foo | Bar) = {
  age: '1',
  name: '1',
  gender: 1
}
// 交集情况,OK
let n: (Foo | Bar) = {
  age: '1',
  name: '1',
}

@se030 se030 mentioned this issue Mar 6, 2023
@lessfish
Copy link
Contributor

@L1atte 你这只是普通的联合类型使用吧,m 匹配到的是 Foo,n 匹配到的是 Bar,和交集并集没啥关系吧

@Mario-Marion
Copy link

666

@DoubleWoodLin
Copy link
Contributor

type T1=Foo&Bar;
type T2=Foo|Bar;
keyof T1会拿到 Foo和Bar的所有key,因为Foo&Bar 相当于把两个对象merge了。
keyof T2会拿到既存在于Foo,也存在于Bar中的key,因为T2有可能是Foo,也有可能是Bar,所以只有拿共同拥有的key才是安全的。

@MohammadArasteh
Copy link

why below code does not pass testcases?
type Diff<O, O1> = Omit<O, keyof O1> | Omit<O1, keyof O>

@DoubleWoodLin
Copy link
Contributor

why below code does not pass testcases? type Diff<O, O1> = Omit<O, keyof O1> | Omit<O1, keyof O>

use '&" replace the '|',and wrap the expression with Omit<exp,never>,such like this:
Omit<Omit<O, keyof O1> & Omit<O1, keyof O>, never>
Diff gets different keys from O and O1,so you can omit the keys which both O and O1 have.And merge the rest keys.
By merging,use ‘&’, not '|'.

@tclxshunquan-wang
Copy link

type Diff<O, O1, K1 extends keyof O = keyof O> = Omit<O & O1, K1 extends keyof O & keyof O1 ? K1 : never>

@Mario-Marion
Copy link

@shun-quan

type Diff<O, O1, K1 extends keyof O = keyof O> = Omit<O & O1, K1 extends keyof O & keyof O1 ? K1 : never>
below is simpler

type Diff<O, O1> = Omit<O & O1, keyof O & keyof O1 >
or
type Diff<O, O1> = Omit<O & O1, keyof (O | O1) >

@Mario-Marion
Copy link

why below code does not pass testcases? type Diff<O, O1> = Omit<O, keyof O1> | Omit<O1, keyof O>

use '&" replace the '|',and wrap the expression with Omit<exp,never>,such like this: Omit<Omit<O, keyof O1> & Omit<O1, keyof O>, never> Diff gets different keys from O and O1,so you can omit the keys which both O and O1 have.And merge the rest keys. By merging,use ‘&’, not '|'.

@DoubleWoodLin
明白了,谢谢

@YuFengDing
Copy link

the keypoint of this question is to understand the differences:

type Result = keyof (Foo | Bar) // 'name' | 'age'
type Result2 = keyof Foo | keyof Bar // 'name' | 'age' | 'gender'

@Math-chen
Copy link

all the answer not consider the same key, but key type difference,
This answer is more rigorous

type Bar = {
  name: string
  age: string
  gender: number
}
type Coo2 = {
  name: number
  gender: number
}

Expect<Equal<Diff<Bar , Coo2>, { name: number; age: string; }>>,
Expect<Equal<Diff<Coo2 , Bar>, { name: string; age: string; }>>,

type Flatten<P> = {
  [key in keyof P]: P[key]
} 

type Equal<X, Y> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2
  ? true
  : false
export type NotEqual<X, Y> = true extends Equal<X, Y> ? false : true

type Diff<O, O1> = Flatten<{
  [key in keyof O as key extends keyof O1? Equal<O[key],O1[key]> extends true? never: key: key ]: key extends keyof O1? O1[key]: O[key]
} & {
  [key in keyof O1 as key extends keyof O? Equal<O[key],O1[key]> extends true? never: key: key]: O1[key]
}>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
645 answer Share answers/solutions to a question en in English
Projects
None yet
Development

No branches or pull requests