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

「重学TS 2.0 」TS 练习题第四十七题 #68

Open
semlinker opened this issue Oct 12, 2021 · 7 comments
Open

「重学TS 2.0 」TS 练习题第四十七题 #68

semlinker opened this issue Oct 12, 2021 · 7 comments

Comments

@semlinker
Copy link
Owner

实现 RequireExactlyOne 工具类型,用于满足以下功能。即只能包含 agegender 属性,不能同时包含这两个属性。具体的使用示例如下所示:

interface Person {
  name: string;
  age?: number;
  gender?: number;
}

// 只能包含Keys中唯一的一个Key
type RequireExactlyOne<T, Keys extends keyof T> = // 你的实现代码

const p1: RequireExactlyOne<Person, 'age' | 'gender'> = {
  name: "lolo",
  age: 7,
};

const p2: RequireExactlyOne<Person, 'age' | 'gender'> = {
  name: "lolo",
  gender: 1
};

// Error
const p3: RequireExactlyOne<Person, 'age' | 'gender'> = {
  name: "lolo",
  age: 7,
  gender: 1
};

请在下面评论你的答案

@zhaoxiongfei
Copy link

interface Person {
  name: string;
  age?: number;
  gender?: number;
  income?: number;
}

// 只能包含Keys中唯一的一个Key
type RequireExactlyOne<T, Keys extends keyof T, K extends keyof T = Keys> = Keys extends any
  ? Omit<T, K> & Required<Pick<T, Keys>> & Partial<Record<Exclude<K, Keys>, never>>
  : never;

type T1 = RequireExactlyOne<Person, "age" | "gender" | "income">;
const p1: T1 = {
  name: "lolo",
  age: 7,
};

const p2: T1 = {
  name: "lolo",
  gender: 1
};

const p3: T1 = {
  name: "lolo",
  income: 100
};

// Error
const p4: T1 = {
  name: "lolo",
  age: 7,
  gender: 1,
};

const p5: T1 = {
  name: "lolo",
  age: 7,
  income: 1,
};

const p6: T1 = {
  name: "lolo",
  gender: 7,
  income: 1,
};

const p7: T1 = {
  name: "lolo",
  age: 8,
  gender: 7,
  income: 1,
};

解题思路: 利用联合类型 extends 实现分布执行,之后重点是 如何让联合类型规则只有其中某一个生效,在每一个上设置哪些禁止的属性为可选 never

@pagnkelly
Copy link

interface Person1 {
  name: string;
  age?: number;
  gender?: number;
}
// 想要构建成这个样子才可以满足条件
type ttt = { name: string } & ({ age: number, gender?: never } | { age?: never, gender: number })

type RP<T, K> = {
  [P in keyof T]: P extends K ? T & Partial<Record<P, never>> : never
}[keyof T];

// 只能包含Keys中唯一的一个Key
type RequireExactlyOne<T, K extends keyof T> = Omit<T, K> & RP<Pick<T, K>, K>

const p1: RequireExactlyOne<Person1, 'age' | 'gender'> = {
  name: "lolo",
  age: 7,
};

const p2: RequireExactlyOne<Person1, 'age' | 'gender'> = {
  name: "lolo",
  gender: 1
};

// Error
const p3: RequireExactlyOne<Person1, 'age' | 'gender'> = {
  name: "lolo",
  age: 7,
  gender: 1
};

@zjxxxxxxxxx
Copy link

type RequireExactlyOne<T, K extends keyof T> = K extends any
  ? Omit<T, K> & Partial<Record<K, never>>
  : never;

@bill-lai
Copy link

type RequireExactlyOne<T, Keys extends keyof T, K extends keyof T = Keys> = 
  Omit<T, K> & Partial<Record<K, never>> | (
    Keys extends any 
      ? Omit<T, K> & Required<Pick<T, Keys>> & Partial<Record<Exclude<K, Keys>, never>>
      : never 
  )

@dolphin0618
Copy link

type RequireExactlyOne<T, K extends keyof T, W extends keyof T = K> = Omit<T, W> & (
  K extends any ? Required<Pick<T, K>> & Partial<Record<Exclude<W, K>, undefined>> : 1
)

@zhengyimeng
Copy link

// 只能包含Keys中唯一的一个Key
type RequireExactlyOne<T, Keys extends keyof T> = Keys extends any
  ? Omit<T, Keys> & { [K in Keys]: never }
  : never;

为啥这样不对呢?

@zhengyimeng
Copy link

// 只能包含Keys中唯一的一个Key
type RequireExactlyOne<T, Keys extends keyof T> = Keys extends any
  ? Omit<T, Keys> & { [K in Keys]?: never }
  : never;

抱歉少了一个 可选

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants